/*----------------------------------------------------------------------------
 * Copyright (c) <2019-2020>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei OMIP(belong to OMSIS) may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 *---------------------------------------------------------------------------*/
#include "omip.h"
#include "omip_log.h"
#include "omip_uart.h"
#include "securec.h"

#include "proxy.h"


typedef enum {
    OMIP_RECEIVE_COMPLETE = 200,
    OMIP_RECEIVE_NONE,
    OMIP_RECEIVE_PARTLY,
    OMIP_RECEIVE_NO_RESOURCE,
    OMIP_RECEIVE_ALREADY_MSG,
    OMIP_RECEIVE_OUT_OF_ORDER,
    OMIP_RECEIVE_INVALID,
    OMIP_RECEIVE_NOT_EXPECT,
}omip_enum_recv_state;

typedef enum {
    OMIP_RECEIVE_NEWMGS,
    OMIP_RECEIVE_NEEDBUF,    
    OMIP_RECEIVE_NEWMSG_ALREADY,
    OMIP_RECEIVE_OLDMSG_ALREADY,
    OMIP_RECEIVE_MSG_NOT_EXPECT,
}omip_enum_recv_order;

typedef struct omip_context_tag omip_context_s;

//first uart buffer
static unsigned char g_recv_buf[OMIP_SUPPORT_MAX_PYS_DEV_NUM][OMIP_UART_RCV_BUFF];

static omip_context_s  *gp_omip_context;

#define OMIP_CRC_TABLE_LEN 256 //CRC8 table length
static const unsigned char g_omip_crc_table[OMIP_CRC_TABLE_LEN] = {
    0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
    0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
    0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
    0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
    0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
    0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
    0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
    0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
    0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
    0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
    0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
    0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
    0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
    0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
    0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
    0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
};

#define OMIP_SYS_CONFIG_DATA_MAX  64
static unsigned char g_sys_config_data[OMIP_SYS_CONFIG_DATA_MAX];
static struct omip_stat_info g_stat_info;

static int omip_init(omip_context_s  **context);

static int omip_recv_callback(void *arg, void *data, unsigned short len);
static int omip_send_sync(omip_send_list *item, unsigned char trans_flags);
static void omip_list_insert_tail(omip_recv_assemble *head,omip_frame_data_list *node);
static void omip_get_frame_list(omip_recv_assemble *head, unsigned char* out_data);
static void omip_free_frame_list(omip_recv_assemble *head);
static int omip_send_deassembly(omip_context_s *core);
static int omip_recv_reassembly(omip_context_s *core, omip_enum_recv_state *rflag);
static unsigned short omip_encode_frame(unsigned char pkg_num, omip_send_list *item, 
    unsigned int offset, unsigned short len, unsigned char trans_flags);
static void omip_send_one_frame(unsigned char* buf, unsigned short len, int io_id);
static unsigned char omip_create_new_sid(unsigned char vc, unsigned short cmd);
static void omip_send_frame(unsigned char pkg_num, omip_send_list *item, unsigned int offset, 
    unsigned short len, unsigned char trans_flags);
static void omip_send_ack(unsigned char vc, unsigned char sid, unsigned char relay_flag, unsigned char relay_vc, omip_ack_info *ack);
static int omip_recv_ack(omip_context_s *contex, omip_frame_data_list *item);
static int omip_decode_frame(omip_context_s *contex, omip_frame_data_list *item, unsigned int io_id);
static int omip_pbuf_malloc_copy(omip_buf_list *head, unsigned int size, unsigned char *data);
static void omip_pbuf_free(omip_buf_list *head);
static int omip_pbuf_copy_part(omip_buf_list *head, unsigned int offset, unsigned short len,
    unsigned char *out_buf, unsigned short out_buf_len);
static int omip_select(omip_context_s *context, unsigned int timeout);
static void omip_send_timeout(omip_context_s *context);
static void omip_reassble_timeout(omip_context_s *context);
static int omip_update_sendwindow(omip_sock *sock);
static int omip_update_recvwindow(omip_sock *sock, unsigned char sid_num);

static omip_enum_recv_order omip_judge_out_of_order(omip_sock *sock, unsigned short cmd, unsigned char cur_sid);
static void omip_free_sendlist(omip_send_list **sendlist);
omip_send_list *omip_add_to_sendlist(omip_context_s *context, omip_transaction *ts);

int omip_recv_connect_req(unsigned char vc, unsigned char sid, unsigned char *data, unsigned short len);
int omip_recv_connect_ack(unsigned char vc, unsigned char sid, unsigned char *data, unsigned short len);
int omip_sys_cmd_handler(void *arg, void *data, unsigned short len);

typedef int (*omip_random_bytes_cb)(void *buf, unsigned int len);
omip_random_bytes_cb omip_random_cb = NULL;

static void omip_init_ackinfo(omip_ack_info *info, unsigned char result,unsigned char exp_sid,
    unsigned char recv_cap, unsigned char exp_fid)
{
    info->result   = result;
    info->exp_sid  = exp_sid;
    info->recv_cap = recv_cap;
    info->exp_fid  = exp_fid;
}

static omip_enum_recv_order omip_out_of_windows(omip_sock *sock, unsigned char cur_sid)
{
    if(sock->recv_sid_flag[cur_sid] == OMIP_GID_PACKET_SENT2USER)
    {
        omip_printf(OMIP_ERROR,"===may receive duplicate msg,sid(%d) when recv,window(%d-%d)!\r\n",
            cur_sid, sock->recv_left_window, sock->recv_right_window);
        return OMIP_RECEIVE_OLDMSG_ALREADY;
    }
    else
    {
        omip_printf(OMIP_ERROR,"===sid(%d) invalid,window(%d-%d).[%s,%d]!!\r\n",
            cur_sid, sock->recv_left_window, sock->recv_right_window,__FUNCTION__,__LINE__);
        return OMIP_RECEIVE_MSG_NOT_EXPECT;
    }
}

void omip_set_random_bytes(omip_random_bytes_cb random)
{
    omip_random_cb = random;
}

int omip_random_bytes(void *buf, unsigned int len)
{
    if (omip_random_cb != NULL)
        omip_random_cb(buf, len);
    return 0;
}
static int omip_recv_callback(void *arg, void *data, unsigned short len)
{
    int ret;
    omip_sock *sock = (omip_sock *)arg;

    ret = osal_queue_send(sock->recv_queue, data, len, cn_osal_timeout_forever);
    if(ret != OSAL_OK)
    {
        omip_recv_assemble *p = (omip_recv_assemble *)data;
        omip_printf(OMIP_ERROR_FLASH,"osal_queue_send failed,cmd:%x,ret:%x.[%s,%d]\r\n",
            p->cmd,ret,__FUNCTION__,__LINE__);
        return OMIP_ERROR_UNKNOWN;
    }
    else
    {
        omip_printf(OMIP_DEBUG,"====queue write ok(qid is %d, len(%d)).[%s,%d]\r\n",
           sock->recv_queue, len,__FUNCTION__,__LINE__);
        return OMIP_OK;
    }
}


static int omip_send_sync(omip_send_list *item, unsigned char trans_flags)
{
    unsigned char  package_num = 0;
    unsigned int offset = 0;
    unsigned int omip_user_data_max_len = OMIP_USER_DATA_MAX_LEN;
    unsigned int left_len = item->tlen;

    omip_printf(OMIP_DEBUG,"====send out,io_flag:%d, sid:%d(%d), cmd:%x, vc:%d, ct:%d, len:%d.\r\n",
        item->ext_io_flag, item->sid,gp_omip_context->sock[item->vc].sid_local_overflow_num, 
        item->cmd, item->vc, item->ct, item->tlen);
    //omip frame or ble data fram(omip over ble)
    if(item->ext_io_flag != OMIP_NOT_ENCODE) {
		while (left_len > omip_user_data_max_len) {
			omip_send_frame(package_num, item, offset, omip_user_data_max_len, trans_flags);
			package_num++;
			left_len -= omip_user_data_max_len;
			offset += omip_user_data_max_len;
		}
        omip_send_frame(package_num, item, offset, (unsigned short)left_len, trans_flags|OMIP_LAST_FRAME);
    }
    else
    {
        omip_printf(OMIP_INFO,"====set ble name,len:%d\r\n",item->pbuf.len);
        for(int i = 0; i < item->pbuf.len;i++)
            omip_printf(OMIP_DEBUG_UPLOAD,"====data:%d\r\n",item->pbuf.payload[i]);
        //ble cmd, send directly, not encode omip frame
        int io_id = 0;
        if(gp_omip_context->workmode == OMIP_WORK_PROXY)
        {
            io_id = omip_get_ioid_byvc(item->vc);
        }
        omip_printf(OMIP_INFO,"====io_id:%d\r\n",io_id);
        for(int i = 0; i < item->pbuf.len; i++)
        {
            omip_send_byte(item->pbuf.payload[i], io_id);
        }
    }

    

    return OMIP_OK;
}


static void omip_list_insert_tail(omip_recv_assemble *head,omip_frame_data_list *node)
{
    omip_frame_data_list *temp;
    temp = head->next;
    while(temp->next !=NULL)
    {
        temp = temp->next;//find the last node
    }
    temp->next = node;
    head->tlen += node->len;
}

static void omip_get_frame_list(omip_recv_assemble *head, unsigned char *out_data)
{
    omip_frame_data_list *temp;
    unsigned char *out_tmp = out_data;
    unsigned short len = 0;
    temp = head->next;
    while(NULL!=temp)
    {
        len = temp->len;
        unsigned char* source_data = temp->u.req.data;
        (void)memcpy_s(out_tmp, len, source_data, len);
        temp = temp->next;
        out_tmp = out_tmp + len;
    }
}

static void omip_free_frame_list(omip_recv_assemble *head)
{
    omip_frame_data_list *p = head->next;
    omip_frame_data_list *pr = NULL;
    while (p != NULL)
    {
        pr = p;
        p = p->next;
        omip_free(pr);
    }
}
static int omip_send_deassembly(omip_context_s *core)
{
    omip_send_list *item ;
    omip_send_list *unack = NULL;
    unsigned char pos;
    unsigned char vc;
    int i;

    for(i = 0;i < core->active_vc_num; i++)
    {
        pos  = core->cur_active_pos;
        vc = core->active_vc[pos];
        if(core->sock[vc].head_unsent != NULL)
        {
            break;
        }
        core->cur_active_pos = (core->cur_active_pos + 1) % (core->active_vc_num);
    }

    if(i >= core->active_vc_num)
    {
        return OMIP_OK;
    }

    if (osal_mutex_lock(core->sock[vc].user_send_mutex) != OSAL_OK)
    {
        return OMIP_ERROR_UNKNOWN;
    }
    item = core->sock[vc].head_unsent;
    core->sock[vc].head_unsent = item->next;
    if(core->sock[vc].unsent_num > 0) core->sock[vc].unsent_num--;
    (void)osal_mutex_unlock(core->sock[vc].user_send_mutex);

    item->next = NULL;

    if(item->fmt == (int)OMIP_CMD_FRAME_CON)
    {
        core->sock[vc].unack_num++;
        if(core->sock[vc].head_unack == NULL)
        {
            core->sock[vc].head_unack = item;
            omip_printf(OMIP_DEBUG,"add to head(%p),cmd(0x%x),sid(%d),vc(%d),ct(%d).[%s,%d] !!!\r\n",
                item,item->cmd, item->sid, item->vc, item->ct, __FUNCTION__, __LINE__);
        }
        else
        {
            unack = core->sock[vc].head_unack;

            while(unack->next)
            {
                unack = unack->next;

            }
            unack->next = item;
            omip_printf(OMIP_DEBUG,"add to tail(%p),cmd(0x%x),sid(%d),vc(%d),ct(%d).[%s,%d] !!!\r\n",
                item,item->cmd, item->sid, item->vc, item->ct, __FUNCTION__, __LINE__);

        }
        omip_send_sync(item, 0);
        if(core->sock[vc].level == OMIP_QOS_2)
        {
            core->sock[vc].send_sid_flag[item->sid] = OMIP_GID_PACKET_WAIT_ACK;
        }

    }
    else
    {
        omip_send_sync(item, 0);
        omip_pbuf_free(&item->pbuf);
        omip_free(item);
    }
    core->cur_active_pos = (core->cur_active_pos + 1) % (core->active_vc_num);
    return OMIP_OK;


}

static int omip_store_first_frame(omip_sock *sock, omip_frame_data_list *node)
{
    int i;
    omip_ack_info ack;
    int not_expect_msg = 0;
    //qos2, not shakehand ok, and not shakehand msg, return error
    if((sock->level == OMIP_QOS_2) && (sock->connect_state != OMIP_CONNECT_STATE_DONE_OK) && 
                (((node->u.req.cmd >> 8) & 0xFF) != OMIP_SYS_CONFIG_CMD_FIELD))
    {
        omip_printf(OMIP_ERROR,"++not expect msg, sid:%d, vc:%d, cmd:%x, connect_state:%d!!!\r\n",
                    node->sid, node->vc, node->u.req.cmd, sock->connect_state);
        return OMIP_ERROR_UNKNOWN;
    }

    //receive not expect msg such as peer retrans msgs with sid not in receive window, local have alread send to user
    if((sock->level == OMIP_QOS_2) && (((node->u.req.cmd >> 8) & 0xFF) != OMIP_SYS_CONFIG_CMD_FIELD))
    {
        if(sock->recv_left_window < sock->recv_right_window) {
            if((node->sid < sock->recv_left_window) || 
                (node->sid >= sock->recv_right_window))
            {
                not_expect_msg = 1;
            }
        }
        else
        {
            if((node->sid < sock->recv_left_window) &&
                (node->sid >= sock->recv_right_window))
            {
                not_expect_msg = 1;
            }
        }
        if(not_expect_msg == 1)
        {
            omip_init_ackinfo(&ack,(unsigned char)OMIP_RECEIVE_NOT_EXPECT,
                sock->recv_left_window,sock->assemble_num, 0);
            if(node->relay_flag == OMIP_NEED_RELAY)
                omip_send_ack(node->relay_vc, node->sid, node->relay_flag, node->vc, &ack);
            else
                omip_send_ack(node->vc, node->sid, OMIP_NOT_NEED_RELAY, 0, &ack);
            omip_printf(OMIP_ERROR,"++not in recv windows(%d-%d), sid:%d, vc:%d, assemble_num:%d!\r\n",
                    sock->recv_left_window, sock->recv_right_window,node->sid, node->vc, sock->assemble_num);
            return OMIP_ERROR_UNKNOWN;
        }
    }

    //judge if in cache
    for(i = 0; i < OMIP_MAX_ASSEMBLE_NUM; i++)
    {
        if(sock->assemble_head[i].used != OMIP_REASSEMBLE_NONE)
        {
            if(sock->assemble_head[i].sid == node->sid)
            {
                omip_printf(OMIP_ERROR,"++has already in cache, sid:%d, vc:%d, assemble_num:%d!\r\n",
                    node->sid, node->vc, sock->assemble_num);
                return OMIP_ERROR_UNKNOWN;    
            }
        }
    }

    //malloc new item
    for(i = 0; i < OMIP_MAX_ASSEMBLE_NUM; i++)
    {
        if(sock->assemble_head[i].used == OMIP_REASSEMBLE_NONE)
        {
            break;
        }
    }
    
    if(i >= OMIP_MAX_ASSEMBLE_NUM)
    {
        omip_printf(OMIP_ERROR,"vc:%d, assemble_num:%d.!!!\r\n",
                node->vc, sock->assemble_num);

        for(int k = 0; k < OMIP_MAX_ASSEMBLE_NUM; k++)
        {
            omip_printf(OMIP_ERROR,"k:%d, used:%d, sid:%d cmd:%x, ctime:%d.!!!\r\n",
                k, sock->assemble_head[k].used,sock->assemble_head[k].sid,sock->assemble_head[k].cmd,
                sock->assemble_head[k].ctime);
        }
        return OMIP_NO_RESOURCE;
    }

    if(node->last_frame == 0)
        sock->assemble_head[i].used = OMIP_REASSEMBLE_ONGOING;
    else
        sock->assemble_head[i].used = OMIP_REASSEMBLE_DONE;
    
    sock->assemble_head[i].relay_flag = node->relay_flag;
    if(sock->assemble_head[i].relay_flag == OMIP_NEED_RELAY)
    {
        sock->assemble_head[i].vc = node->relay_vc;
        sock->assemble_head[i].relay_vc = node->vc;
    }
    else
    {
    sock->assemble_head[i].vc = node->vc;
        sock->assemble_head[i].relay_vc = 0;
    }
    
    sock->assemble_head[i].sid = node->sid;
    sock->assemble_head[i].exp_fnum = ((node->fid + 1)%(OMIP_FIDNUM_MAX+1));//max fid is 0xff ,fid can overflow
    sock->assemble_head[i].ct = node->ct;
    sock->assemble_head[i].tlen += node->len;
    sock->assemble_head[i].cmd = node->u.req.cmd;
    sock->assemble_head[i].next = node;
    sock->assemble_head[i].ctime = (unsigned int)osal_sys_time();    
    
    if(sock->assemble_num > 0) --sock->assemble_num;

    return i;
}
static int omip_store_following_frame(omip_sock *sock, omip_frame_data_list *node)
{
    int i;
    for(i = 0; i < OMIP_MAX_ASSEMBLE_NUM; i++)
    {
        if((sock->assemble_head[i].used == 1) &&
            (sock->assemble_head[i].vc == node->vc) &&
            (sock->assemble_head[i].sid == node->sid) &&
            (sock->assemble_head[i].exp_fnum == node->fid))
        {
            break;
        }

    }
    if(i >= OMIP_MAX_ASSEMBLE_NUM)
    {
        omip_printf(OMIP_ERROR,"====not expect following frame,vc:%d,sid:%d,fid:%d,cannot assemble.[%s,%d]!!!\r\n",
            node->vc,node->sid,node->fid,__FUNCTION__,__LINE__);
        return OMIP_FRAME_NOT_EXP;
    }

    omip_list_insert_tail(&sock->assemble_head[i],node);

    sock->assemble_head[i].exp_fnum = ((node->fid + 1)%(OMIP_FIDNUM_MAX+1));//max fid is 0xff ,fid can overflow
    
    if(node->last_frame == 1)
        sock->assemble_head[i].used = OMIP_REASSEMBLE_DONE;
    
    return i;

}

static int omip_recv_reassembly(omip_context_s *core, omip_enum_recv_state *rflag)
{
    omip_sock *sock;
    int i,j;
    int len = 0;
    omip_ack_info ack;
    unsigned char cur_vc;
    unsigned char cur_sid;
    unsigned short cur_cmd;
    unsigned char cur_relay_flag;
    unsigned char cur_relay_vc;
    
    omip_frame_data_list *frame;
    unsigned char node_id;



    for(i = 0; i < OMIP_SUPPORT_MAX_PYS_DEV_NUM; i++)
    {
        if(core->io_p[core->cur_io_p_id]->skb_read_index != core->io_p[core->cur_io_p_id]->skb_write_index)
        {
            break;
        }
        if((core->cur_io_p_id + 1) < OMIP_SUPPORT_MAX_PYS_DEV_NUM)
            core->cur_io_p_id += 1;
        else
            core->cur_io_p_id = 0;
        
    }

    if(i >= OMIP_SUPPORT_MAX_PYS_DEV_NUM)
    {
         *rflag = OMIP_RECEIVE_NONE;
         return 0;
    }

    frame = (omip_frame_data_list *)omip_malloc(sizeof(omip_frame_data_list));
    if(frame == NULL)
    {
        omip_printf(OMIP_ERROR,"====malloc node failed.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        *rflag = OMIP_RECEIVE_INVALID;
        return len;
    }
    (void)memset_s(frame, sizeof(omip_frame_data_list), 0, sizeof(omip_frame_data_list));
    int ret = omip_decode_frame(core, frame, core->cur_io_p_id);
    
    if(core->workmode == OMIP_WORK_PROXY)
    {
        if(frame->relay_flag == OMIP_NEED_RELAY) {
            //relay msg
            node_id = omip_get_ioid_byvc(frame->relay_vc);
            if(node_id >= OMIP_SUPPORT_MAX_PYS_DEV_NUM)
            {
                omip_printf(OMIP_ERROR,"====get relay node_id failed,relay vc:%d.\r\n",
                    frame->relay_vc);
                *rflag = OMIP_RECEIVE_INVALID;
                omip_free(frame);
                return 0;
            }
            omip_printf(OMIP_DEBUG,"====get relay node_id:%d,relay vc:%d,sid:%d,realy to next destination...\r\n",
                    node_id, frame->relay_vc,frame->sid);
            
            omip_send_one_frame(frame->origin_frame,frame->origin_frame_len,node_id);
            omip_free(frame);
            *rflag = OMIP_RECEIVE_COMPLETE;
            return 0;
        } 
        else {
            // deliver to user
            omip_printf(OMIP_DEBUG,"====vc:%d,sid:%d, will deliver to local APP...\r\n",frame->vc,frame->sid);
            sock = (core->sock + frame->vc);
        }
    }
    else
    {
        //receive by endpoint,such as module or mobilephone app
        if(frame->relay_flag == OMIP_NEED_RELAY)
            sock = (core->sock + frame->relay_vc);
        else
            sock = (core->sock + frame->vc);
    }

    if(ret != OMIP_OK)
    {
        omip_printf(OMIP_ERROR,"====omip_decode_frame failed or para error(vc:%d, sid:%d, ret:%d).\r\n",
            ret,frame->vc, frame->sid);
        *rflag = OMIP_RECEIVE_INVALID;
        omip_free(frame);
        return len;
    }


    if(sock->used == 0)
    {
        omip_printf(OMIP_ERROR,"====sock->used(%d) not opened.[%s,%d]\r\n",frame->vc,__FUNCTION__,__LINE__);
        *rflag = OMIP_RECEIVE_INVALID;
        omip_free(frame);
        return 0;
    }

    if(frame->ftype != OMIP_FRAME_ACK)
    {
        g_stat_info.recvreqnum++;
        len = frame->len;
        if(frame->fid == 0)//only one packet for sid, or  first packet,need reassmble
        {
            if((i = omip_store_first_frame(sock, frame)) < 0)
            {
                omip_printf(OMIP_ERROR,"====some errors, first frame is discarded!\r\n");
                omip_free(frame);
                *rflag = OMIP_RECEIVE_NO_RESOURCE;
                return 0;
            }

        }
        else // not first packet, so need find which head to push
        {
            if((i = omip_store_following_frame(sock, frame)) < 0)
            {
                omip_printf(OMIP_ERROR,"====not expect following frame,vc:%d,sid:%d,fid:%d,cannot assemble!\r\n",
                    frame->vc,frame->sid,frame->fid);
                omip_free(frame);
                *rflag = OMIP_RECEIVE_INVALID;
                return 0;
            }
        }

        if(frame->last_frame != 0)
        {   
            if(sock->level != OMIP_QOS_0)
            {
                omip_enum_recv_order order = omip_judge_out_of_order(sock, frame->u.req.cmd, frame->sid);
                if((order == OMIP_RECEIVE_MSG_NOT_EXPECT) || (order == OMIP_RECEIVE_OLDMSG_ALREADY) || (order == OMIP_RECEIVE_NEWMSG_ALREADY))
                {
                
                    omip_printf(OMIP_INFO,"====not new msg(order:%d),sid:%d(%d),exp_sid(%d),cmd:%d, frametype:%d!\r\n",
                        order, frame->sid,sock->sid_remote_overflow_num, sock->exp_sid, frame->u.req.cmd,frame->ftype);
                    omip_init_ackinfo(&ack, (unsigned char)order,
                        sock->recv_left_window, sock->assemble_num, 0);
                    if(frame->relay_flag == OMIP_NEED_RELAY)
                        omip_send_ack(frame->relay_vc, frame->sid, frame->relay_flag, frame->vc, &ack);
                    else
                        omip_send_ack(frame->vc, frame->sid, OMIP_NOT_NEED_RELAY, 0, &ack);

                    omip_free_frame_list(&sock->assemble_head[i]);
                    (void)memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]), 0, sizeof(sock->assemble_head[i]));
                    sock->assemble_num++;
                    if(order == OMIP_RECEIVE_MSG_NOT_EXPECT)
                    {
                        *rflag = OMIP_RECEIVE_NOT_EXPECT;
                        sock->recv_not_expt_msg++;
                        if(sock->recv_not_expt_msg > 5)
                        {
                            // restart shakehand now...
                        }
                    }
                    else
                    {
                        *rflag = OMIP_RECEIVE_ALREADY_MSG;
                    }
                    return 0;
                }
                else if(order == OMIP_RECEIVE_NEEDBUF)
                {
                    omip_printf(OMIP_INFO,"====receive msg need bufering...,sid:%d(%d),exp_sid(%d),cmd:%d, frametype:%d !!!\r\n",
                        frame->sid, sock->sid_remote_overflow_num, sock->exp_sid, frame->u.req.cmd,frame->ftype);
                    omip_init_ackinfo(&ack, (unsigned char)OMIP_RECEIVE_COMPLETE,
                        sock->recv_left_window, sock->assemble_num, 0);
                    if(frame->relay_flag == OMIP_NEED_RELAY)
                        omip_send_ack(frame->relay_vc, frame->sid, frame->relay_flag, frame->vc, &ack);
                    else
                        omip_send_ack(frame->vc, frame->sid, OMIP_NOT_NEED_RELAY, 0, &ack);
                    
                    *rflag = OMIP_RECEIVE_COMPLETE;
                    return 0;
                }

                *rflag = OMIP_RECEIVE_COMPLETE;
                //when send to user ,then node and node->data will be free
                //so save node->vc, node->sid
                cur_vc  = frame->vc;
                cur_sid = frame->sid;
                cur_cmd = frame->u.req.cmd;
                cur_relay_flag = frame->relay_flag;
                cur_relay_vc = frame->relay_vc;

                if(((cur_cmd >> 8) & 0xFF) == OMIP_SYS_CONFIG_CMD_FIELD)
                {
                    omip_sys_cmd_handler(sock, &sock->assemble_head[i],sizeof(sock->assemble_head[i]));
                }

                if(sock->recv_cb(sock, &sock->assemble_head[i],
                    (unsigned short)sizeof(sock->assemble_head[i])) != OMIP_OK)
                {
                    omip_printf(OMIP_ERROR,"====send to user failed(sid:%d, cmd:%d),wait retrans\r\n",
                        cur_sid,cur_cmd);
                    omip_free_frame_list(&sock->assemble_head[i]);
                    (void)memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]), 0, sizeof(sock->assemble_head[i]));
                    sock->assemble_num++;
                    return 0;
                }
                if(sock->last_sid_send2user == OMIP_SID_MAX)
                {
                    sock->sid_remote_overflow_num++;
                }
                sock->last_sid_send2user = cur_sid;
                (void)memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]), 0, sizeof(sock->assemble_head[i]));
                sock->assemble_num++;
                //maybe continue to send buffering msg to user
                int k;
                int cc;
                for(j = 1; j < OMIP_RECV_WINDOW_SIZE; j++)
                {
                    cc = cur_sid + j;
                    if(cc >= (OMIP_SID_MAX+1))
                    {
                        cc = cc - (OMIP_SID_MAX+1);
                    }
                    if(sock->recv_sid_flag[cc] == OMIP_GID_PACKET_WAITING)
                    {
                        for(k = 0; k < OMIP_MAX_ASSEMBLE_NUM; k++)
                        {
                            if((sock->assemble_head[k].used == OMIP_REASSEMBLE_DONE) && 
                                (sock->assemble_head[k].sid == cc))
                            {
                                break;
                            }
                        }
                        if(k >= OMIP_MAX_ASSEMBLE_NUM)
                        {
                            omip_printf(OMIP_ERROR_FLASH,"====impossble error(buffering sid:%d.\r\n",
                                cc);
                            sock->recv_sid_flag[cc] = OMIP_GID_PACKET_SENT2USER;
                            continue;
                        }
                        omip_printf(OMIP_ERROR,"++++send to user continue,sid:%d(%d),cmd:%x.\r\n",
                        cc,sock->sid_remote_overflow_num,sock->assemble_head[k].cmd);
                        if(sock->recv_cb(sock, &sock->assemble_head[k],
                            (unsigned short)sizeof(sock->assemble_head[k])) != OMIP_OK)
                        {
                            omip_printf(OMIP_ERROR,"====send to user failed(sid:%d, cmd:%d)\r\n",
                                cc,sock->assemble_head[k].cmd);
                            omip_free_frame_list(&sock->assemble_head[k]);
                            (void)memset_s(&sock->assemble_head[k], sizeof(sock->assemble_head[k]), 0, sizeof(sock->assemble_head[k]));
                            sock->assemble_num++;
                            continue;
                       }
                        if(sock->last_sid_send2user == OMIP_SID_MAX)
                        {
                            sock->sid_remote_overflow_num++;
                        }
                        sock->last_sid_send2user = cc;
                       (void)memset_s(&sock->assemble_head[k], sizeof(sock->assemble_head[k]), 0, sizeof(sock->assemble_head[k]));
                       sock->assemble_num++;
                        
                    }
                    else
                    {
                        break;
                    }
                }
                
                
                if(((cur_cmd >> 8) & 0xFF) != OMIP_SYS_CONFIG_CMD_FIELD) {
                    omip_update_recvwindow(sock, j);
                    omip_init_ackinfo(&ack, (unsigned char)OMIP_RECEIVE_COMPLETE,
                        sock->recv_left_window,sock->assemble_num,0);
                    if(cur_relay_flag == OMIP_NEED_RELAY)
                        omip_send_ack(cur_relay_vc, cur_sid, cur_relay_flag, cur_vc, &ack);
                    else
                        omip_send_ack(cur_vc, cur_sid, OMIP_NOT_NEED_RELAY, 0, &ack);
                    
                }

            }
            else
            {

                *rflag = OMIP_RECEIVE_COMPLETE;
                omip_printf(OMIP_DEBUG, "====recv msg, sid:%d,cmd:%x.[%s,%d]\r\n",
                    frame->sid, frame->u.req.cmd, __FUNCTION__,__LINE__);

                if(sock->recv_cb(sock, &sock->assemble_head[i],sizeof(sock->assemble_head[i])) != OMIP_OK)
                {
                    omip_free_frame_list(&sock->assemble_head[i]);
                }
                (void)memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]), 0, sizeof(sock->assemble_head[i]));
                sock->assemble_num++;
            }


        }
        else
        {
            *rflag = OMIP_RECEIVE_PARTLY;
        }
     }
     else
     {
         *rflag = OMIP_RECEIVE_COMPLETE;
         omip_recv_ack(core,frame);
         omip_free(frame);
     }

     if((core->cur_io_p_id + 1) < OMIP_SUPPORT_MAX_PYS_DEV_NUM)
        core->cur_io_p_id += 1;
    else
        core->cur_io_p_id = 0;
    

     return len;
}

//Support one frame
static unsigned short omip_encode_frame(unsigned char pkg_num, omip_send_list *item, 
    unsigned int offset, unsigned short len, unsigned char trans_flags)
{
    unsigned short j = 0;
    unsigned char crc = 0;
    unsigned short i = 0;
    unsigned char *psend = gp_omip_context->send_frame_buf;
    unsigned char frametype;

    (void)memset_s(psend, OMIP_FRM_MAX_LEN, 0, OMIP_FRM_MAX_LEN);
    // head
    psend[j] = OMIP_START;
    j++;

    // virtual channel,high 4bits
    // relay channel,low 4bits
    psend[j] = ((item->vc<<4) & 0xF0);
    if(item->relay_flag == OMIP_NEED_RELAY)
    {
        psend[j] |= (item->relay_vc & 0x0F);
    }
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;

    // sid
    psend[j] = item->sid;
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;

    // fid
    psend[j] = pkg_num;
    //calc crc from package_num
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;

    //bit 7: if last frame. 1:last frame, 0:not last frame.
    //bit 6: retransflag,frame retrans bit
    //bit 5 relay flag.
    //bit 4 reserved.
    //low 4bit: frame type.
    psend[j] = trans_flags;
    if(item->relay_flag == OMIP_NEED_RELAY)
    {
        psend[j] |= OMIP_RELAY_VALID;
    }
    frametype = (item->fmt & 0x0F);
    psend[j] |= frametype;
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;
    
    // high 4bit: payload content format
    // low 4bit reserved for encryt
    psend[j] = ((item->ct<<4) & 0xF0);
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;
    
    // high 8bits len
    psend[j] = ((len >> 8) & 0xFF);
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;

    // low 8bits length
    psend[j] = len & 0xFF;
    crc = g_omip_crc_table[crc ^ psend[j]];
    j++;
    
    //ack no cmd
    if(frametype != (int)OMIP_FRAME_ACK) {
        // command region and command set
        psend[j] = ((item->cmd >> 8) & 0xFF);
        crc = g_omip_crc_table[crc ^ psend[j]];
        j++;
        // command
        psend[j] = (item->cmd & 0xFF);
        crc = g_omip_crc_table[crc ^ psend[j]];
        j++;
    }
    /* val , 2 means start and end character*/
    omip_pbuf_copy_part(&item->pbuf, offset, len, &psend[j], (OMIP_FRM_MAX_LEN - j - 2));
    for (i = 0; i < len; i++) {
        crc = g_omip_crc_table[crc ^ psend[j]];
        j++;
    }

    /* CRC */
    psend[j] = crc;
    j++;
    if(frametype != (unsigned char)OMIP_FRAME_ACK){
        omip_printf(OMIP_DEBUG,"====send cmd frame,vc(%d),cmd(%x),sid(%d),fid(%d),crc(0x%x),len(%d).[%s,%d]\r\n",
            item->vc,item->cmd,item->sid, pkg_num,crc,len,__FUNCTION__,__LINE__);
    }
    else
    {
        omip_printf(OMIP_DEBUG,"====send ack frame,vc(%d),sid(%d),fid(%d),crc(0x%x),len(%d).[%s,%d]\r\n",
            item->vc,item->sid, pkg_num,crc,len,__FUNCTION__,__LINE__);
    }
    /* Flag */
    psend[j] = OMIP_END;
    
    return (j + 1);
}

void omip_send_one_frame(unsigned char* buf, unsigned short len, int io_id)
{
    unsigned short i = 0;

    omip_print_io_bytes(buf, len, 1, io_id);
    //send frame head OMIP_END
    omip_send_byte(buf[0], io_id);
    i++;

    //deal OMIP_END or OMIP_ESC of frame data
    for (; i < len - 1; i++)
    {
        switch (buf[i]) {
            case OMIP_START:
                omip_send_byte(OMIP_ESC, io_id);
                omip_send_byte(OMIP_ESC_START, io_id);
                break;
            case OMIP_END:
                omip_send_byte(OMIP_ESC, io_id);
                omip_send_byte(OMIP_ESC_END, io_id);
                break;
            case OMIP_ESC:
                omip_send_byte(OMIP_ESC, io_id);
                omip_send_byte(OMIP_ESC_ESC, io_id);
                break;
            default:
                omip_send_byte(buf[i], io_id);
                break;
        }
    }

    //send frame end OMIP_END
    omip_send_byte(buf[i], io_id);
}

static unsigned char omip_create_new_sid(unsigned char vc, unsigned short cmd)
{
    omip_sock *sock = &gp_omip_context->sock[vc];
    unsigned char sid = sock->sid;
    if(((cmd >> 8) & 0xFF) == OMIP_SYS_CONFIG_CMD_FIELD)
    {
        sock->sid++;
        if(sock->sid > OMIP_SID_MAX)
        {
            sock->sid_local_overflow_num++;
            sock->sid = OMIP_SID_MIN;
        }
        sock->send_left_window = (((unsigned char)(sock->sid)) % (OMIP_SID_MAX+1));
        sock->send_right_window = (((unsigned char)(sock->sid+OMIP_SEND_WINDOW_SIZE)) % (OMIP_SID_MAX+1));
        return sid;
    }
    
    if(sock->level == OMIP_QOS_2)
    {
        if(sock->send_left_window < sock->send_right_window) {
            if((sid < sock->send_left_window) || 
                (sid >= sock->send_right_window))
            {
                return 0xFF; 
            }
        }
        else
        {
            if((sid < sock->send_left_window) &&
                (sid >= sock->send_right_window))
            {
                return 0xFF;
            }
        }
        sock->send_sid_flag[sid] = OMIP_GID_PACKET_NO_SENT;
    }
    
    sock->sid++;
    if(sock->sid > OMIP_SID_MAX)
    {
        sock->sid_local_overflow_num++;
        sock->sid = OMIP_SID_MIN;
    }
    
    return sid;
}

static void omip_send_frame(unsigned char pkg_num, omip_send_list *item, 
    unsigned int offset, unsigned short len, unsigned char trans_flags)
{
    unsigned int io_id = 0;

    omip_context_s *context = gp_omip_context;
    
    
    unsigned short frame_len = omip_encode_frame(pkg_num, item, offset, len, trans_flags);
    //relay trans not in here,but in omip_recv_reassembly
    if(gp_omip_context->workmode == OMIP_WORK_PROXY)
    {
        io_id = omip_get_ioid_byvc(item->vc);
        if(io_id >= OMIP_SUPPORT_MAX_PYS_DEV_NUM)
        {
            omip_printf(OMIP_ERROR,"get io_id failed,vc(%d),sid(%d),len(%d).\r\n",
            item->vc,item->sid, pkg_num, len);
            return;
    }
    }
    omip_io_paras  *io_p = context->io_p[io_id];
    omip_printf(OMIP_DEBUG,"io:%d,inject_send:%p\n",io_id,io_p->inject_send);
    io_p->inject_send(gp_omip_context->send_frame_buf,frame_len, io_id);
}



// receive one byte according slip_uart UART_FLAG_RXNE interrupt
void omip_receive_byte(unsigned char data, int io_id)
{
    unsigned char receive_data = data;
    omip_io_paras *io_p = gp_omip_context->io_p[io_id];
    //the last received data is OMIP_ESC
    if (io_p->is_ESC == 1) {
        // data is not OMIP_ESC_END or OMIP_ESC_ESC,ignore this frame
        if ((receive_data != OMIP_ESC_END) && (receive_data != OMIP_ESC_ESC) && (receive_data != OMIP_ESC_START)) {
            io_p->cur_frame_len = 0;
            io_p->is_ESC = 0;
            io_p->is_receive_frame_head = 0;

            io_p->skb_buf[io_p->skb_write_index].len = 0;
            io_p->skb_buf[io_p->skb_write_index].pos = io_p->write_index;
        }
    }

    //received frame head
    if(receive_data == OMIP_START)
    {
        io_p->is_receive_frame_head = 1;
        //todo:optimize if the recbuf will full
        if ((OMIP_UART_RCV_BUFF - io_p->write_index) < OMIP_FRM_MAX_LEN)
        {
            io_p->write_index = 0;
        }
        
        io_p->skb_buf[io_p->skb_write_index].pos = io_p->write_index;
        io_p->rcvbuf[io_p->write_index] = receive_data;
        io_p->write_index++;
        io_p->cur_frame_len++;
        if (io_p->write_index == OMIP_UART_RCV_BUFF)
        {
            io_p->write_index = 0;
        }
        g_stat_info.recvebytesnum++;
        return;
    }

    if(io_p->is_receive_frame_head == 1)
    {
        switch (receive_data) {
            case OMIP_END:
                // receive two OMIP_END
                io_p->is_receive_frame_head = 0;
                if (io_p->cur_frame_len == 1)//only receive start and end
                {
                    return;
                }
                io_p->rcvbuf[io_p->write_index] = receive_data;
                io_p->write_index++;
                io_p->cur_frame_len++;
                io_p->skb_buf[io_p->skb_write_index].len = io_p->cur_frame_len;
                io_p->cur_frame_len = 0;
                io_p->is_ESC = 0;
                io_p->skb_write_index++;
                if(io_p->skb_write_index >= OMIP_UART_SKB_NUM)
                {
                    io_p->skb_write_index = 0;
                }
                g_stat_info.recvebytesnum++;
                g_stat_info.recvemsgsnum++;
                osal_semp_post(gp_omip_context->io_tx_rx_sem);//receive one frame
                break;
            case OMIP_ESC:
                io_p->is_ESC = 1;
                break;
             case OMIP_ESC_START:
                if (io_p->is_ESC == 1) {
                    receive_data = OMIP_START;
                    io_p->is_ESC = 0;
                }
                io_p->cur_frame_len++;
                io_p->rcvbuf[io_p->write_index] = receive_data;
                io_p->write_index++;
                g_stat_info.recvebytesnum++;
                break;
            case OMIP_ESC_END:
                if (io_p->is_ESC == 1) {
                    receive_data = OMIP_END;
                    io_p->is_ESC = 0;
                }
                io_p->cur_frame_len++;
                io_p->rcvbuf[io_p->write_index] = receive_data;
                io_p->write_index++;
                g_stat_info.recvebytesnum++;
                break;
            case OMIP_ESC_ESC:
                if (io_p->is_ESC == 1) {
                    receive_data = OMIP_ESC;
                    io_p->is_ESC = 0;
                }
                io_p->cur_frame_len++;
                io_p->rcvbuf[io_p->write_index] = receive_data;
                io_p->write_index++;
                g_stat_info.recvebytesnum++;
                break;
            default:
                io_p->cur_frame_len++;
                io_p->rcvbuf[io_p->write_index] = receive_data;
                io_p->write_index++;
                g_stat_info.recvebytesnum++;
                break;
        }
    }

    if (io_p->write_index == OMIP_UART_RCV_BUFF)
    {
        io_p->write_index = 0;
    }


}


static void omip_send_ack(unsigned char vc, unsigned char sid, unsigned char relay_flag, unsigned char relay_vc, omip_ack_info *ack)
{
    omip_send_list head = {0};
    unsigned int io_id = 0;

    if(relay_flag == OMIP_NEED_RELAY)
    {
        head.vc         = vc;
        head.relay_flag = OMIP_NEED_RELAY;
        head.relay_vc   = relay_vc;
    }
    else
    {
    head.vc  = vc;
    }
    
    head.sid = sid;
    head.fmt = OMIP_FRAME_ACK;
    

    g_stat_info.sendacknum++;
    head.tlen = sizeof(*ack);
    omip_pbuf_malloc_copy(&head.pbuf, sizeof(*ack),(unsigned char *)ack);
    omip_printf(OMIP_DEBUG,"send ack, vc:%d,sid:%d,relay_flag:%d,relay_vc:%d.[%s,%d]\n",
        head.vc,head.sid,relay_flag,relay_vc, __FUNCTION__,__LINE__);
    unsigned short frame_len = omip_encode_frame(0x80,&head,0,(unsigned short)sizeof(*ack),OMIP_LAST_FRAME);
    if(gp_omip_context->workmode == OMIP_WORK_PROXY) {
        io_id = omip_get_ioid_byvc(vc);
    }
    
    omip_send_one_frame(gp_omip_context->send_frame_buf,frame_len,io_id);

    omip_pbuf_free(&head.pbuf);
}

static int omip_recv_ack(omip_context_s *context, omip_frame_data_list *item)
{
    omip_send_list *unack = NULL;
    omip_send_list *before = NULL;
    omip_ack_info *ack = &item->u.ack;
    unsigned char vc;
    unsigned int delay;

    if(item->relay_flag == OMIP_NEED_RELAY)
    {
        vc = item->relay_vc;
    }
    else
    {
        vc = item->vc;
    }

    omip_printf(OMIP_DEBUG, "recv ack, vc:%d, sid:%d, unack_num:%d,exp_sid:%d.[%s,%d]\n",
        vc,item->sid,context->sock[vc].unack_num,ack->exp_sid,__FUNCTION__,__LINE__);

    context->sock[vc].peer_exp_sid  = ack->exp_sid;
    g_stat_info.recvacknum++;
    if((ack->result != (unsigned char)OMIP_RECEIVE_COMPLETE) &&
        (ack->result != (unsigned char)OMIP_RECEIVE_ALREADY_MSG))
    {
        omip_printf(OMIP_ERROR,"====bad ack,result:%d,exp_sid:%d,recv_cap:%d.[%s,%d]\r\n",
            ack->result,ack->exp_sid,ack->recv_cap,__FUNCTION__,__LINE__);
        g_stat_info.recvacknum_bad++;
    }


    unack  = context->sock[vc].head_unack;
    before = context->sock[vc].head_unack;

    while(unack != NULL)
    {
        if((unack->vc == vc) && (unack->sid == item->sid))
        {
            break;
        }
        before = unack;
        unack = unack->next;
    }

    if(unack != NULL)
    {
        //update window
        if(context->sock[vc].level == OMIP_QOS_2)
        {
            context->sock[vc].send_sid_flag[unack->sid] = OMIP_GID_PACKET_RECV_ACK;
            if(unack->sid == context->sock[vc].send_left_window)
            {
                omip_update_sendwindow(&context->sock[vc]);    
            }
        }
        
        
        if(unack  == context->sock[vc].head_unack)
        {
            context->sock[vc].head_unack = unack->next;
        }
        else
        {
            before->next = unack->next;
        }

        if(context->sock[vc].unack_num > 0) --context->sock[vc].unack_num;
        g_stat_info.recvacknum_good++;
        if(g_stat_info.max_retrans < unack->tmo.retran_times)
        {
            g_stat_info.max_retrans = unack->tmo.retran_times;
        }
        unsigned int new_time = (unsigned int)osal_sys_time();
        if(new_time >= unack->tmo.send_cur_time)
            delay = new_time - unack->tmo.send_cur_time;
        else
            delay = 0xFFFFFFFF-unack->tmo.send_cur_time+1+new_time;
        
        if(g_stat_info.max_delay < delay)g_stat_info.max_delay = delay;
        
        omip_printf(OMIP_DEBUG, "cur_time:%d.\n",osal_sys_time());
        omip_printf(OMIP_DEBUG, "delay:%d,find item(%p) from ack(unack num now:%d),vc:%d,sid:%d,cmd:%x.\n",
            delay,unack,context->sock[vc].unack_num,vc,item->sid,unack->cmd);
        omip_pbuf_free(&unack->pbuf);
        omip_free(unack);
    }
    else
    {
        g_stat_info.recvacknum_not_found++;
        omip_printf(OMIP_ERROR,"cannot find item,maybe receive old msg!!!vc:%d, sid:%d.[%s,%d]\n",
            vc,item->sid,__FUNCTION__,__LINE__);
    }



    return OMIP_OK;
}

static int omip_decode_frame(omip_context_s *contex, omip_frame_data_list *item, unsigned int io_id)
{
    omip_io_paras *io_p;
    unsigned short frame_pos;
    unsigned short frame_len;
    unsigned char *data;
    unsigned char crc = 0;
    
    io_p = contex->io_p[io_id];
    frame_pos = io_p->skb_buf[io_p->skb_read_index].pos;
    frame_len = io_p->skb_buf[io_p->skb_read_index].len;
    data = io_p->rcvbuf;
    data = data +frame_pos;

    
    if(frame_len == 0) {
        if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
            io_p->skb_read_index = 0;
        }
        return OMIP_ERROR_UNKNOWN;
    }
    if (frame_len > OMIP_FRM_MAX_LEN || frame_len <= 2) {
        omip_printf(OMIP_ERROR,"====receive frame data len(%d) invalid.[%s,%d]\r\n",
            frame_len,__FUNCTION__,__LINE__);
        //ignor this frame
        if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
            io_p->skb_read_index = 0;
        }
        return OMIP_LENGTH_INVALID;
    }

    omip_print_io_bytes(data, frame_len, 0, io_id);
    if((frame_pos + frame_len) > OMIP_UART_RCV_BUFF)
    {
        omip_printf(OMIP_ERROR,"====receive frame data len(%d) ,over buffer.[%s,%d]\r\n",
            frame_len,__FUNCTION__,__LINE__);
        //ignor this frame
        if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
            io_p->skb_read_index = 0;
        }
        return OMIP_LENGTH_INVALID;
    }
    //check crc
    for (unsigned short i = 1; i < (frame_len - 2); i++)
    {
        crc = g_omip_crc_table[crc ^ (io_p->rcvbuf[frame_pos + i])];
    }
    if (crc != io_p->rcvbuf[frame_pos + frame_len - 2])
    {
        if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
            io_p->skb_read_index = 0;
        }
        omip_printf(OMIP_ERROR,"====len:%d, crc error(0x%x, 0x%x),(%x-%x-%x-%x-%x-%x-%x),%d.[%s,%d]\r\n",
            frame_len,crc,io_p->rcvbuf[frame_pos + frame_len - 2],
            data[0],data[1],data[2],data[3],data[4],data[5],data[6],frame_len,
            __FUNCTION__,__LINE__);
        return OMIP_CRC_ERROR;
    }
    //first start
    data++;

    //get vc
    item->vc = ((data[0]&0xF0) >> 4);
    if(item->vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
            io_p->skb_read_index = 0;
        }
        omip_printf(OMIP_ERROR,"====receive data,vc(%d) invalid.[%s,%d]\r\n",
            item->vc,__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }
    item->relay_vc = (data[0]&0x0F);
    data++;

    //get sid(session id)
    item->sid= *data;
    data++;

    //get fid(frame id)
    item->fid = *data;
    data++;

    //get trans flag
    item->last_frame    = ((data[0] >> 7) & 1);
    item->retrans       = ((data[0] >> 6) & 1);
    item->relay_flag    = ((data[0] >> 5) & 1);
    //frame type
    item->ftype = (data[0] & 0xF);
    data++;
    
    //content format
    item->ct = ((data[0]>>4) & 0xF);
    data++;
    
    //get length (16 bits)
    item->len = ((data[0]&0xF) << 8) | data[1];
    data += 2;
    
    if(item->len > OMIP_USER_DATA_MAX_LEN)
    {
        if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
            io_p->skb_read_index = 0;
        }
        omip_printf(OMIP_ERROR,"====receive data,item->len(%d) invalid.[%s,%d]\r\n",
            item->len,__FUNCTION__,__LINE__);
        return OMIP_ERROR_UNKNOWN;
    }
    if(item->ftype != OMIP_FRAME_ACK)
    {
        //cmd
        item->u.req.cmd      = ((data[0] << 8) | data[1]);
        data = data + 2;


        omip_printf(OMIP_DEBUG,"recv msg(io_id:%d), msgtype(%d), sid:%x, vc:%d,fid:%x,len:%d,cmd:%x.[%s,%d]\n",
            io_id,item->ftype, item->sid, item->vc, item->fid,
            item->len,item->u.req.cmd,__FUNCTION__,__LINE__);
        for (int i = 0; i < item->len; i++)
        {
            item->u.req.data[i]= *data;
            data++;
        }

    }
    else
    {
        item->u.ack.result   = *data++;
        item->u.ack.exp_sid  = *data++;
        item->u.ack.recv_cap = *data;
    }

    item->origin_frame     = (io_p->rcvbuf + frame_pos);
    item->origin_frame_len = frame_len;

    if(++io_p->skb_read_index >= OMIP_UART_SKB_NUM) {
        io_p->skb_read_index = 0;
    }

    return OMIP_OK;
}

static int omip_pbuf_malloc_copy(omip_buf_list *head, unsigned int size, unsigned char *data)
{
    int ret = -1;
    unsigned short insize = size;
    omip_buf_list *next = NULL, *prev = NULL;
    unsigned char *p = data;


    if(insize == 0)
    {
        omip_printf(OMIP_DEBUG,"insize is zero.[%s,%d]!!!\r\n",__FUNCTION__,__LINE__);
        return 0;
    }

    if(insize <= OMIP_PBUF_PAYLOAD_MAX)
    {
        head->payload  = omip_malloc(insize);
        if(head->payload == NULL)
        {
            omip_printf(OMIP_ERROR,"payload is NULL.[%s,%d]\r\n",__FUNCTION__,__LINE__);
            return OMIP_MALLOC_FAILED;
        }
        head->len      = insize;
        ret = memcpy_s(head->payload, insize, p, insize);
        if (ret != EOK) {
            return OMIP_ERROR_UNKNOWN;
        }
    }
    else
    {
        head->payload  = omip_malloc(OMIP_PBUF_PAYLOAD_MAX);
        if(head->payload == NULL)
        {
            omip_printf(OMIP_ERROR,"payload is NULL.[%s,%d]\r\n",__FUNCTION__,__LINE__);
            return OMIP_MALLOC_FAILED;
        }
        head->len    = OMIP_PBUF_PAYLOAD_MAX;
        ret = memcpy_s(head->payload, OMIP_PBUF_PAYLOAD_MAX, p, OMIP_PBUF_PAYLOAD_MAX);
        if (ret != EOK) {
            return OMIP_ERROR_UNKNOWN;
        }

        p            += OMIP_PBUF_PAYLOAD_MAX;
        insize       -= OMIP_PBUF_PAYLOAD_MAX;

        prev = head;
        while(insize > OMIP_PBUF_PAYLOAD_MAX)
        {
            next           = omip_malloc(sizeof(*next));
            if(next == NULL)
            {
                omip_printf(OMIP_ERROR,"next is NULL.[%s,%d]\r\n",__FUNCTION__,__LINE__);
                return OMIP_MALLOC_FAILED;
            }
            (void)memset_s(next, sizeof(*next), 0, sizeof(*next));
            next->payload  = omip_malloc(OMIP_PBUF_PAYLOAD_MAX);
            if(next->payload == NULL)
            {
                omip_printf(OMIP_ERROR,"payload is NULL![%s,%d]\r\n",__FUNCTION__,__LINE__);
                return OMIP_MALLOC_FAILED;
            }
            next->len      = OMIP_PBUF_PAYLOAD_MAX;
            ret = memcpy_s(next->payload, OMIP_PBUF_PAYLOAD_MAX, p, OMIP_PBUF_PAYLOAD_MAX);
            if (ret != EOK) {
                return OMIP_ERROR_UNKNOWN;
            }

            p              += OMIP_PBUF_PAYLOAD_MAX;
            insize         -= OMIP_PBUF_PAYLOAD_MAX;

            prev->next     = next;
            prev           = next;

        }

        next           = omip_malloc(sizeof(*next));
        if(next == NULL)
        {
            omip_printf(OMIP_ERROR,"next is NULL![%s,%d]\r\n",__FUNCTION__,__LINE__);
            return OMIP_MALLOC_FAILED;
        }
        (void)memset_s(next, sizeof(*next), 0, sizeof(*next));
        next->payload  = omip_malloc(insize);
        if(next->payload == NULL)
        {
            omip_printf(OMIP_ERROR,"payload is NULL![%s,%d]\r\n",__FUNCTION__,__LINE__);
            return OMIP_MALLOC_FAILED;
        }
        next->len      = insize;
        ret = memcpy_s(next->payload, insize, p, insize);
        if (ret != EOK) {
            return OMIP_ERROR_UNKNOWN;
        }

        prev->next     = next;

    }

    omip_printf(OMIP_DETAIL,"omip_pbuf_malloc_copy, len is %d.[%s,%d]\r\n", size,__FUNCTION__,__LINE__);
    return size;
}

static void omip_pbuf_free(omip_buf_list *head)
{
    omip_buf_list *next = NULL, *item = NULL;


    next = head;
    while(next != NULL)
    {
        item = next;
        next = next->next;

        if(item->payload)
        {
            omip_free(item->payload);
        }
        if(item != head) //head cannot free
        {
            omip_free(item);
        }
    }

}

static int omip_pbuf_copy_part(omip_buf_list *head, unsigned int offset, unsigned short len,
    unsigned char *out_buf, unsigned short out_buf_len)
{
    int ret = -1;
    omip_buf_list *next = head;
    unsigned short       insize = offset;
    unsigned short       cp_len = 0, cp_len_next = 0;
    unsigned char *inner_buf = out_buf;
    if(len == 0 || len > out_buf_len)
    {
        return 0;
    }
    while(insize >= OMIP_PBUF_PAYLOAD_MAX)
    {
        if(next)next = next->next;
        insize -= OMIP_PBUF_PAYLOAD_MAX;
    }

    if(next == NULL)return OMIP_ERROR_UNKNOWN;

    if((OMIP_PBUF_PAYLOAD_MAX - insize) >= len)
    {
        ret = memcpy_s(inner_buf, len, &next->payload[insize], len);
        if (ret != EOK) {
            return OMIP_ERROR_UNKNOWN;
        }
    }
    else
    {
        cp_len = OMIP_PBUF_PAYLOAD_MAX - insize;
        ret = memcpy_s(inner_buf, cp_len, &next->payload[insize], cp_len);
        if (ret != EOK) {
            return OMIP_ERROR_UNKNOWN;
        }

        inner_buf += cp_len;

        next = next->next;
        cp_len_next = len - (OMIP_PBUF_PAYLOAD_MAX - insize);
        if(next != NULL)
        {
            ret = memcpy_s(inner_buf, cp_len_next, &next->payload[0], cp_len_next);
            if (ret != EOK) {
                return OMIP_ERROR_UNKNOWN;
            }

            cp_len += cp_len_next;
        }
    }

    return cp_len;


}

static int omip_select(omip_context_s *context, unsigned int timeout)
{
    int ret;

    ret = osal_semp_pend(context->io_tx_rx_sem, timeout);
    if(ret == OSAL_OK)
    {
        return OMIP_OK;
    }
    else if(ret == OSAL_TIMEOUT)
    {
        return OMIP_TIMEOUT;
    }
    else
    {
        return OMIP_ERROR_UNKNOWN;
    }
}

static void omip_send_timeout(omip_context_s *context)
{
    unsigned int curtime;
    unsigned int timeout = 0;
    omip_send_list *next = NULL;


    curtime = (unsigned int)osal_sys_time();

    if(curtime >= context->ctime)
    {
        if((curtime - context->ctime) > OMIP_SELECT_TIMEOUT)
        {
            timeout = 1;
            context->ctime = curtime;
        }
    }
    else
    {
        timeout = 1;
        context->ctime = curtime;
    }

    if(timeout == 0)
    {
        return;
    }
    for(int i = 0;i < context->active_vc_num; i++)
    {

        unsigned char vc = context->active_vc[i];
        if(context->sock[vc].head_unack == NULL)
        {
            continue;
        }
        next = context->sock[vc].head_unack;
        while(next != NULL)
        {
            curtime = (unsigned int)osal_sys_time();
            omip_printf(OMIP_DEBUG,"judge(%p),sid:%d, cmd:%x, next->tmo.rtime:%d,peer_exp_gid:%d!\r\n",
                next, next->sid,next->cmd, next->tmo.rtime,gp_omip_context->sock[next->vc].peer_exp_sid);
            if(next->tmo.rtime > 0)--next->tmo.rtime;

            if(next->tmo.rtime == 0)
            {
                if(next->tmo.retrans != 0) {
                    curtime = (unsigned int)osal_sys_time();
                    omip_printf(OMIP_INFO,"--retrans msg(%d),sid:%d,cmd:%x,retrans:%d,curtime:%d,peer_exp_sid:%d!\r\n",
                        next->tmo.retran_times,next->sid,next->cmd, next->tmo.retrans,curtime,gp_omip_context->sock[next->vc].peer_exp_sid);
                    if(next->tmo.retran_times < 5)
                    {
                        next->tmo.rtime = (1 + next->tmo.retran_times)*OMIP_RETRANS_SILICE;
                    }
                    else
                    {
                        next->tmo.rtime = (10 * OMIP_RETRANS_SILICE);
                    }
                    next->tmo.retran_times++;
                    omip_send_sync(next, OMIP_FRAME_RETRANS);
                    
                    if(next->tmo.retrans > 0)
                    {
                        --next->tmo.retrans;
                    }
                }

            }
            //retrans packet for ever,since omip is simple peer to peer
#if 0
            if(next->tmo.retrans == 0)
            {
                //omip_printf(OMIP_ERROR,"release msg(%p),cmd:%x,sid:%x !!!\r\n",next,next->cmd,next->sid);
                item = next;
                next = next->next;
                //omip_printf(OMIP_ERROR,"now next:%p !!!\r\n", next);
                if(item == context->sock[vc].head_unack)
                {
                    context->sock[vc].head_unack = next;
                }
                else
                {
                    if(prev != NULL)
                    {
                        prev->next = next;
                    }
                }
                omip_pbuf_free(&item->pbuf);
                //omip_printf(OMIP_ERROR,"will release item:%p !!!\r\n", item);
                omip_free(item);
                context->sock[vc].unack_num--;
                continue;
            }

            prev = next;
#endif

            next = next->next;

        }

    }

}

static void omip_reassble_timeout(omip_context_s *context)
{
    unsigned int curtime;
    omip_sock *sock;

    curtime = (unsigned int)osal_sys_time();

    for(int j = 0;j < context->active_vc_num; j++)
    {

        unsigned char vc = context->active_vc[j];
        sock = &context->sock[vc];

        for(int i = 0; i <  OMIP_MAX_ASSEMBLE_NUM; i++)
        {
            if(sock->assemble_head[i].used == OMIP_REASSEMBLE_NONE)
            {
                continue;
            }

            if(curtime >= sock->assemble_head[i].ctime)
            {
                if((curtime - sock->assemble_head[i].ctime) > OMIP_REASSBLE_TIMEOUT)
                {
                    omip_printf(OMIP_ERROR_FLASH,"reassble timeout,used:%d,(%x-%x-%x)![%s,%d]\r\n",
                        sock->assemble_head[i].used, sock->assemble_head[i].vc,sock->assemble_head[i].sid,sock->assemble_head[i].cmd,
                        __FUNCTION__,__LINE__);
                    omip_free_frame_list(&sock->assemble_head[i]);
                    (void)memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]), 0, sizeof(sock->assemble_head[i]));
                    sock->assemble_num++;
                }
            }
            else /*overlap*/
            {
                if((0xFFFFFFFF - sock->assemble_head[i].ctime + curtime + 1) > OMIP_REASSBLE_TIMEOUT)
                {
                    omip_printf(OMIP_ERROR_FLASH,"reassble timeout (%x-%x-%x)![%s,%d]\r\n",
                        sock->assemble_head[i].vc,sock->assemble_head[i].sid,sock->assemble_head[i].cmd,
                        __FUNCTION__,__LINE__);
                    omip_free_frame_list(&sock->assemble_head[i]);
                    (void)memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]), 0, sizeof(sock->assemble_head[i]));
                    sock->assemble_num++;
                }
            }
        }
    }
}

static int omip_update_sendwindow(omip_sock *sock)
{
    unsigned char win_sid;
    int i;
    unsigned char gid_num = 0;

    for(i = 0; i < OMIP_SEND_WINDOW_SIZE; i++)
    {
        win_sid = (((unsigned char)(sock->send_left_window+i))%(OMIP_SID_MAX+1));
        if(sock->send_sid_flag[win_sid] == OMIP_GID_PACKET_RECV_ACK)
        {
            sock->send_sid_flag[win_sid] = OMIP_GID_FREE;
            gid_num++;
        }
        else
        {
            break;
        }
    }

    sock->send_left_window = ((unsigned char)(sock->send_left_window + gid_num))%(OMIP_SID_MAX+1);
    sock->send_right_window = ((unsigned char)(sock->send_right_window + gid_num))%(OMIP_SID_MAX+1);

    omip_printf(OMIP_DEBUG,"omip_update_sendwindow,gidnum:%d, sock->send_left_window:%d,right:%d.\n",
        gid_num,sock->send_left_window, sock->send_right_window);
    
    return OMIP_OK;
    
}

static int omip_update_recvwindow(omip_sock *sock, unsigned char gid_num)
{
    unsigned char last_left_window = ((unsigned char)(sock->recv_left_window - OMIP_SEND_WINDOW_SIZE))%(OMIP_SID_MAX+1);
    unsigned char old_sid;
    unsigned char new_sid;

    for(unsigned int i = 0; i < gid_num; i++)
    {
        old_sid = (((unsigned char)(last_left_window+i))%(OMIP_SID_MAX+1));
        new_sid = (((unsigned char)(sock->recv_right_window+i))%(OMIP_SID_MAX+1));
        if(sock->recv_sid_flag[old_sid] != OMIP_GID_NO_PACKET)
        {
            sock->recv_sid_flag[old_sid] = OMIP_GID_NO_PACKET;
        }

        if(sock->recv_sid_flag[new_sid] != OMIP_GID_NO_PACKET)
        {
            sock->recv_sid_flag[new_sid] = OMIP_GID_NO_PACKET;
        }
    }

    sock->recv_left_window = ((unsigned char)(sock->recv_left_window + gid_num))%(OMIP_SID_MAX+1);
    sock->recv_right_window = ((unsigned char)(sock->recv_right_window + gid_num))%(OMIP_SID_MAX+1);

    omip_printf(OMIP_DEBUG,"====omip_update_recvwindow,gid_num:%d,left:%d,right:%d.\r\n",
                                gid_num,sock->recv_left_window,sock->recv_right_window);

    return OMIP_OK;
    
}


static omip_enum_recv_order omip_judge_out_of_order(omip_sock *sock, unsigned short cmd, unsigned char cur_sid)
{
    

    omip_printf(OMIP_DEBUG,"recv msg,sid(%d),cmd(%x),when recv,window(%d-%d).!!\r\n",
                    cur_sid,cmd, sock->recv_left_window, sock->recv_right_window);
    
    if(sock->level != OMIP_QOS_2)
    {
        return OMIP_RECEIVE_NEWMGS;
    }

    if(((cmd >> 8) & 0xFF) == OMIP_SYS_CONFIG_CMD_FIELD)
    {
        return OMIP_RECEIVE_NEWMGS;
    }

    if(sock->recv_left_window < sock->recv_right_window) {
        if((cur_sid < sock->recv_left_window) || 
                (cur_sid >= sock->recv_right_window))
        {
            return omip_out_of_windows(sock, cur_sid);
        }
    }
    else
    {
        if((cur_sid < sock->recv_left_window) &&
                (cur_sid >= sock->recv_right_window))
        {
            return omip_out_of_windows(sock, cur_sid);
        }
    }
    
    if(cur_sid == sock->recv_left_window)
    {
        sock->recv_sid_flag[cur_sid] = OMIP_GID_PACKET_SENT2USER;
        omip_printf(OMIP_DEBUG,"===exactly good,send to user, sid:%d(%d),recv,window(%d-%d).!!\r\n",
                cur_sid,sock->sid_remote_overflow_num,sock->recv_left_window, sock->recv_right_window);
        return OMIP_RECEIVE_NEWMGS;
    }

    if(sock->recv_sid_flag[cur_sid] == OMIP_GID_NO_PACKET)
    {
        sock->recv_sid_flag[cur_sid] = OMIP_GID_PACKET_WAITING;
        omip_printf(OMIP_INFO,"===msg will be buffered, sid(%d),recv,window(%d-%d).[%s,%d]!!\r\n",
                cur_sid,sock->recv_left_window, sock->recv_right_window,__FUNCTION__,__LINE__);
        return OMIP_RECEIVE_NEEDBUF;
    }
    else if(sock->recv_sid_flag[cur_sid] == OMIP_GID_PACKET_WAITING)
    {
        omip_printf(OMIP_INFO,"===already buffering this msg, sid(%d),recv,window(%d-%d).[%s,%d]!!\r\n",
                cur_sid,sock->recv_left_window, sock->recv_right_window,__FUNCTION__,__LINE__);
        return OMIP_RECEIVE_NEWMSG_ALREADY;
    }
    else
    {
        omip_printf(OMIP_ERROR,"===sid:%d,flag:%d invalid when recv,window(%d-%d),maybe old msg sent to user.!!\r\n",
                cur_sid,sock->recv_sid_flag[cur_sid], sock->send_left_window, sock->send_right_window);
        return OMIP_RECEIVE_MSG_NOT_EXPECT;
    }


}

omip_send_list *omip_add_to_sendlist(omip_context_s *context, omip_transaction *ts)
{
    omip_send_list *item;

    if(((ts->cmd >> 8) & 0xFF) != OMIP_SYS_CONFIG_CMD_FIELD)
    {
        if((context->sock[ts->vc].unsent_num + context->sock[ts->vc].unack_num) >= OMIP_SEND_QUEUE_LIST_MAX)
        {
            return NULL;
        }
    }
    omip_send_list *new_item = (omip_send_list *)omip_malloc(sizeof(omip_send_list));
    if(new_item == NULL)
    {
       omip_printf(OMIP_ERROR,"====omip_malloc failed in omip_api_send,cmd is %x.[%s,%d]\r\n", ts->cmd,__FUNCTION__,__LINE__);
       return NULL;
    }

    (void)memset_s(new_item, sizeof(*new_item), 0, sizeof(*new_item));
    new_item->next           = NULL;
    new_item->tmo.retrans    = OMIP_RETRANS_TIMES;
    new_item->tmo.rtime      = OMIP_RETRANS_SILICE;
    new_item->vc             = ts->vc;
    new_item->ct             = ts->ctf;
    new_item->relay_flag     = ts->relay_flag;
    new_item->relay_vc       = ts->relay_vc;
    new_item->ext_io_flag    = ts->ext_io_flag;

    if((context->sock[ts->vc].level == OMIP_QOS_0) || (((ts->cmd >> 8) & 0xFF) == OMIP_SYS_CONFIG_CMD_FIELD)
        || (ts->ext_io_flag == OMIP_NOT_ENCODE))
        new_item->fmt        = OMIP_CMD_FRAME_NON;
    else
        new_item->fmt        = OMIP_CMD_FRAME_CON;
    new_item->cmd            = ts->cmd;
    new_item->tlen           = ts->len;


    if(omip_pbuf_malloc_copy(&new_item->pbuf, ts->len, ts->data) < 0)
    {
        omip_printf(OMIP_ERROR_FLASH,"====omip_pbuf_malloc_copy failed,len:%d.[%s,%d]!!\r\n",ts->len,__FUNCTION__,__LINE__);
        omip_pbuf_free(&new_item->pbuf);
        omip_free(new_item);
        return NULL;
    }
    if(osal_mutex_lock(context->sock[ts->vc].user_send_mutex) != OSAL_OK)
    {
        omip_pbuf_free(&new_item->pbuf);
        omip_free(new_item);
        return NULL;
    }
    new_item->sid            = omip_create_new_sid(ts->vc, ts->cmd);

    if(new_item->sid == 0xFF)
    {
        omip_printf(OMIP_ERROR_FLASH,"====cannot get new sid...cur:%d,sendleft:%d,right:%d!\r\n",
            context->sock[ts->vc].sid,
            context->sock[ts->vc].send_left_window,
            context->sock[ts->vc].send_right_window);
        
        (void)osal_mutex_unlock(context->sock[ts->vc].user_send_mutex);
        omip_pbuf_free(&new_item->pbuf);
        omip_free(new_item);
        return NULL;
    }

    if(context->sock[ts->vc].head_unsent == NULL)
    {
        context->sock[ts->vc].head_unsent = new_item;

    }
    else
    {
        item = context->sock[ts->vc].head_unsent;
        while(item->next)
            item = item->next;
        item->next = new_item;
    }
    if(((ts->cmd >> 8) & 0xFF) != OMIP_SYS_CONFIG_CMD_FIELD)
    {
        context->sock[ts->vc].unsent_num++;
    }
    
    (void)osal_mutex_unlock(context->sock[ts->vc].user_send_mutex);
    osal_semp_post(context->io_tx_rx_sem);
    return new_item;
}



omip_context_s  *omip_get_context(void)
{
    return gp_omip_context;
}

void* omip_malloc(unsigned int size)
{
    return osal_malloc(size);
}

void omip_free(void* addr)
{
    osal_free(addr);
}

static int omip_init(omip_context_s  **context)
{
    int ret;
    int i;

    omip_context_s *p_omip_core = omip_malloc(sizeof(*p_omip_core));
    if(p_omip_core == NULL)
    {
        return OMIP_MALLOC_FAILED;
    }
    (void)memset_s(p_omip_core, sizeof(*p_omip_core), 0, sizeof(*p_omip_core));

    

    ret = osal_mutex_create(&p_omip_core->active_vc_mutex);
    if (ret != OSAL_OK)
    {
        omip_free(p_omip_core);
        omip_printf(OMIP_ERROR,"====active_vc_mutex create failed ![%s,%d]\r\n",__FUNCTION__,__LINE__);
    	return OMIP_ERROR_UNKNOWN;
    }

    omip_io_paras *io_p = omip_malloc(sizeof(*io_p) * OMIP_SUPPORT_MAX_PYS_DEV_NUM);
    if(io_p == NULL)
    {
        omip_free(p_omip_core);
        return OMIP_MALLOC_FAILED;
    }
    (void)memset_s(io_p, sizeof(*io_p)*OMIP_SUPPORT_MAX_PYS_DEV_NUM, 0, sizeof(*io_p)*OMIP_SUPPORT_MAX_PYS_DEV_NUM);
    for(i = 0;  i < OMIP_SUPPORT_MAX_PYS_DEV_NUM; i++)
    {
        p_omip_core->io_p[i]              = io_p+i;
        (void)memset_s(g_recv_buf[i], OMIP_UART_RCV_BUFF, 0, OMIP_UART_RCV_BUFF);
        p_omip_core->io_p[i]->rcvbuf      = g_recv_buf[i];
        p_omip_core->io_p[i]->rcvbuf_len  = OMIP_UART_RCV_BUFF;
        p_omip_core->io_p[i]->inject_send = omip_send_one_frame;
        p_omip_core->io_p[i]->inject_recv_byte = omip_receive_byte;
    }
    
    omip_sock *sock_array = omip_malloc(sizeof(*sock_array)*OMIP_VC_CHANNEL_TOTAL);
    if(sock_array == NULL)
    {
        omip_free(p_omip_core);
        omip_free(io_p);
        return OMIP_MALLOC_FAILED;
    }

    (void)memset_s(sock_array, sizeof(*sock_array)*OMIP_VC_CHANNEL_TOTAL, 0, sizeof(*sock_array)*OMIP_VC_CHANNEL_TOTAL);
    for(i = 0; i < (int)OMIP_VC_CHANNEL_TOTAL; i++)
    {
        sock_array[i].exp_sid = 0xFF;
    }
    p_omip_core->sock = sock_array;

    ret = osal_semp_create(&p_omip_core->io_tx_rx_sem, 256, 0);
    if (ret != OSAL_OK)
    {
        omip_free(p_omip_core);
        omip_free(io_p);
        omip_free(sock_array);
        return OMIP_ERROR_UNKNOWN;
    }
    *context = p_omip_core;
    omip_printf(OMIP_INFO,"====omip init succ,ver:%s![%s,%d]\r\n",OMIP_VER,__FUNCTION__,__LINE__);
    return OMIP_OK;
}

static void omip_free_sendlist(omip_send_list **sendlist)
{
    if(sendlist == NULL || *sendlist == NULL)
    {
        return;
    }

    omip_send_list *next = *sendlist;
    omip_send_list *item;

    while(next)
    {
        item = next;
        next = item->next;
        omip_pbuf_free(&item->pbuf);
        omip_free(item);
    }
    *sendlist = next;
}

static void omip_deinit(omip_context_s **context)
{
    omip_context_s *temp;
    int i;

    temp = *context;
    *context = NULL;//cannot send msg;
    osal_task_sleep(1000);

    for(int j = 0;j < temp->active_vc_num; j++)
    {
        unsigned char vc = temp->active_vc[j];
        omip_sock *sock = &temp->sock[vc];
        for(i = 0; i < OMIP_MAX_ASSEMBLE_NUM; i++)
        {
            if(sock->assemble_head[i].used)
            {
                omip_free_frame_list(&sock->assemble_head[i]);
            }
        }
        omip_free_sendlist(&sock->head_unsent);
        omip_free_sendlist(&sock->head_unack);
        osal_mutex_del(sock->user_send_mutex);
        osal_queue_del(sock->recv_queue);
        (void)memset_s(sock, sizeof(*sock), 0, sizeof(*sock));
    }

    osal_semp_del(temp->io_tx_rx_sem);

    omip_io_paras *io_p = temp->io_p[0];
    
    omip_free(temp->sock);
    omip_free(io_p);
    omip_free(temp);
    omip_printf(OMIP_INFO,"====omip deinit succ![%s,%d]\r\n",__FUNCTION__,__LINE__);
}

int omip_work_task_entry(void *args)
{

    //unsigned int rec_times=0;
    omip_context_s *context = (omip_context_s *)args;
    omip_enum_recv_state rstate;
    if(context == NULL)
    {
        return -1 ;
    }
    unsigned int old_time = osal_sys_time();
    unsigned int cur_time = osal_sys_time();
    while(1)//do the loop here
    {
        //rec_times ++ ;
        cur_time = osal_sys_time();
        
        rstate = OMIP_RECEIVE_INVALID;
        omip_select(context, OMIP_SELECT_TIMEOUT);
        omip_recv_reassembly(context, &rstate); //recv one msg
        if(rstate == OMIP_RECEIVE_PARTLY)
        {
            if(cur_time >= old_time)
            {
                if((cur_time - old_time) > 10000)
                {
                    omip_printf(OMIP_DEBUG,"====##++omip loop works now![%s,%d]\r\n",__FUNCTION__,__LINE__);
                    old_time = cur_time;
                }
            }
            else
            {
                omip_printf(OMIP_DEBUG,"====#++--++omip loop works2 now![%s,%d]\r\n",__FUNCTION__,__LINE__);
                old_time = cur_time;
            }
            continue;//continue to receive one user msg
        }
        omip_reassble_timeout(context);
        omip_send_timeout(context);    //judge if timeout
        omip_send_deassembly(context); //send one msg

        if(cur_time >= old_time)
        {
            if((cur_time - old_time) > 10000)
            {
                omip_printf(OMIP_DEBUG,"====++omip loop works now![%s,%d]\r\n",__FUNCTION__,__LINE__);
                old_time = cur_time;
            }
        }
        else
        {
            omip_printf(OMIP_DEBUG,"====++--++omip loop works2 now![%s,%d]\r\n",__FUNCTION__,__LINE__);
            old_time = cur_time;
        }
    }

    return 0;
}

void omip_start_work_task(void *arg, unsigned short taskpri, unsigned int stack)
{
    if(arg == NULL)
    {
        omip_printf(OMIP_ERROR,"====arg is NULL in omip_start_work_task![%s,%d]\r\n",__FUNCTION__,__LINE__);
        return;
    }
    gp_omip_context->work_handle = osal_task_create("omip_work_task_entry", omip_work_task_entry, arg, stack, NULL, taskpri);
}
static int omip_add_vc_to_active(omip_context_s *context, unsigned char vc)
{
    int i = 0;
    if (osal_mutex_lock(context->active_vc_mutex) != OSAL_OK)
    {
        return OMIP_ERROR_UNKNOWN;
    }

    for(;i< context->active_vc_num;i++)
    {
        if(vc == context->active_vc[i])
        {
            break;
        }

    }
    if(i >= context->active_vc_num)
    {
        context->active_vc[context->active_vc_num] = vc;
        context->active_vc_num++;
    }
    (void)osal_mutex_unlock(context->active_vc_mutex);
    return OMIP_OK;
}

int omip_set_workmode(omip_workmode mode)
{
    if(gp_omip_context == NULL)
    {
        omip_printf(OMIP_ERROR,"====gp_omip_context is NULL.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        return OMIP_MALLOC_FAILED;
    }
    if((((int)mode) < ((int)OMIP_WORK_CONTROLER)) || (((int)mode) >= ((int)OMIP_WORK_INVALID)))
    {
        return OMIP_PARAS_INVALID;
    }
    gp_omip_context->workmode = mode;

    return OMIP_OK;
}

int omip_open_vc(unsigned char vc, omip_qos_level level, const char *app_name, unsigned char support_auth)
{
    int ret;
    omip_sock *sock;
    omip_recv_assemble msg;
    unsigned short msg_len = (unsigned short)sizeof(msg);

    (void)app_name;
    if(gp_omip_context == NULL)
    {
        omip_printf(OMIP_ERROR,"====gp_omip_context is NULL.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        return OMIP_MALLOC_FAILED;
    }

    if(vc < OMIP_VC_CHANNEL_RESERVED || vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR,"====vc can only be from 4 to 15.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }
    sock = &gp_omip_context->sock[vc];
    if(sock->used != 0)
    {
        return OMIP_OK;
    }
    switch(level) {
        case OMIP_QOS_0:
        case OMIP_QOS_1:
        case OMIP_QOS_2:
            break;
        default:
        {
            omip_printf(OMIP_ERROR,"====level(%d) is invalid.[%s,%d]\r\n",(int)level,__FUNCTION__,__LINE__);
            return OMIP_QOS_INVALID;
        }
    }

    (void)memset_s(sock, sizeof(*sock), 0, sizeof(*sock));
    sock->exp_sid = 0xFF;
    sock->peer_exp_sid = 0xFF;
    sock->level = level;
    sock->assemble_num = OMIP_MAX_ASSEMBLE_NUM;
    if(level == OMIP_QOS_2) {
        sock->recv_left_window = 0;
        sock->recv_right_window = OMIP_RECV_WINDOW_SIZE;
    
        sock->send_left_window = 0;
        sock->send_right_window = OMIP_SEND_WINDOW_SIZE;
    }
    ret = osal_queue_create(&sock->recv_queue,OMIP_QUEUE_LEN_DEFAULT,msg_len);
    if (ret != OSAL_OK)
    {
        omip_printf(OMIP_ERROR,"====osal_queue_create omip_api_recv failed,ret %d.[%s,%d]\n",ret,__FUNCTION__,__LINE__);
        return OMIP_ERROR_UNKNOWN;
    }
    ret = osal_mutex_create(&sock->user_send_mutex);
    if (ret != OSAL_OK)
    {
        osal_queue_del(sock->recv_queue);
        omip_printf(OMIP_ERROR,"====user_send_mutex create failed ![%s,%d]\r\n",__FUNCTION__,__LINE__);
    	return OMIP_ERROR_UNKNOWN;
    }
    sock->recv_cb    = omip_recv_callback;
    sock->recv_arg   = sock;
    sock->support_auth = !!support_auth;

    sock->used     = 1;
    omip_add_vc_to_active(gp_omip_context, vc); 
    
    omip_printf(OMIP_INFO_FLASH,"====open vc(%d) succ,qos:%d.[%s,%d]\r\n",vc,level,__FUNCTION__,__LINE__);
    return OMIP_OK;


}

int omip_close_vc(unsigned char vc, const char *app_name)
{
    omip_context_s *context = gp_omip_context;

    (void)app_name;
    if(vc < OMIP_VC_CHANNEL_RESERVED || vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR,"====vc(%d) is invalid, only can be from 4 to 15.[%s,%d]\r\n",
            vc,__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }

    if(context->sock[vc].used == 0)
    {
        return OMIP_VC_NOT_OPENED;
    }
    osal_mutex_del(context->sock[vc].user_send_mutex);
    osal_queue_del(context->sock[vc].recv_queue);
    (void)memset_s(&context->sock[vc], sizeof(context->sock[vc]), 0, sizeof(context->sock[vc]));

    return OMIP_OK;
}

int omip_send(omip_transaction *ts)
{
    omip_context_s  *context = gp_omip_context;
    omip_send_list *item = NULL;
    
    unsigned int start_time,end_time,delta = 0;
    int timeout = (int)ts->timeout;
    
    start_time = osal_sys_time();
    if(ts == NULL)
    {
        return OMIP_POINTER_NULL;
    }

    if((ts->data == NULL && ts->len != 0) || (ts->data != NULL && ts->len == 0))
    {
        omip_printf(OMIP_ERROR_FLASH,"====error,data:%p, len:%d.[%s,%d]\r\n",ts->data, ts->len, __FUNCTION__,__LINE__);
        return OMIP_PARAS_INVALID;
    }

    if(ts->len > (OMIP_FIDNUM_MAX * OMIP_USER_DATA_MAX_LEN))
    {
        omip_printf(OMIP_ERROR_FLASH,"====len err,data len:%d.[%s,%d]\r\n", ts->len,__FUNCTION__,__LINE__);
        return OMIP_LENGTH_INVALID;
    }

    if(ts->vc < OMIP_VC_CHANNEL_RESERVED || ts->vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR_FLASH,"====vc(%d) is invalid, only can be from 4 to 15.[%s,%d]\r\n",ts->vc,__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }

    if(ts->relay_flag == OMIP_NEED_RELAY)
    {
        if(ts->relay_vc < OMIP_VC_CHANNEL_RESERVED || ts->relay_vc >= (int)OMIP_VC_CHANNEL_TOTAL)
        {
            omip_printf(OMIP_ERROR_FLASH,"====relay_vc(%d) is invalid, only can be from 4 to 15.[%s,%d]\r\n",ts->relay_vc,__FUNCTION__,__LINE__);
            return OMIP_VC_INVALID;
        }
    }

    if(ts->ctf >= OMIP_CONTENT_FORMAT_INVALID)
    {
        omip_printf(OMIP_ERROR_FLASH,"====ct(%d) is invalid, only can be from 0 to 3.[%s,%d]\r\n",ts->ctf,__FUNCTION__,__LINE__);
        return OMIP_CT_INVALID;
    }

    if((context == NULL) || (context->sock[ts->vc].used == 0))
    {
        omip_printf(OMIP_ERROR,"====context(%p),vc(%d) is not opened.[%s,%d]\r\n",context,ts->vc,__FUNCTION__,__LINE__);
        return OMIP_VC_NOT_OPENED;
    }
    if(((ts->cmd >> 8) & 0xFF) != OMIP_SYS_CONFIG_CMD_FIELD) 
    {
        if((context->sock[ts->vc].level == OMIP_QOS_2) && (context->sock[ts->vc].connect_state != OMIP_CONNECT_STATE_DONE_OK))
        {
            omip_printf(OMIP_ERROR,"====vc(%d) is not connected(%d),cmd:%x.[%s,%d]\r\n",
            ts->vc,context->sock[ts->vc].connect_state,ts->cmd,__FUNCTION__,__LINE__);
            return OMIP_VC_NOT_OPENED;
        }
    }

    end_time = osal_sys_time();
    if(start_time <= end_time)
    {
        delta = end_time - start_time;
    }
    else 
    {
        delta = end_time + (0xFFFFFFFF - start_time + 1);
    }
    
    //if failed, there is nothing can do
    
    if(ts->timeout == OMIP_WAIT_FOREVER) {
        while((item = omip_add_to_sendlist(context, ts)) == NULL)
        {
            osal_task_sleep(10);
        }
    }
    else
    {
        timeout -= delta;
        while(timeout >= 0)
        {
            start_time = osal_sys_time();
            if((item = omip_add_to_sendlist(context, ts)) != NULL)
            {
                break;
            }
            osal_task_sleep(10);
            end_time = osal_sys_time();
            if(start_time <= end_time)
            {
                delta = end_time - start_time;
            }
            else 
            {
                delta = end_time + (0xFFFFFFFF - start_time + 1);
            }
            timeout -= delta;
        }

        if(timeout < 0)
        {
            omip_printf(OMIP_ERROR_FLASH,"====send timeout(%d),vc:%d,cmd:%x,unsent:%d,unack:%d\r\n",
                ts->timeout, ts->vc, ts->cmd, gp_omip_context->sock[ts->vc].unsent_num, gp_omip_context->sock[ts->vc].unack_num);
            g_stat_info.send_failed++;
            return OMIP_BUF_FULL;
        }
        else
        {
            item->tmo.send_cur_time = osal_sys_time();
            omip_printf(OMIP_DEBUG, "====add to list succ,vc:%d,sid:%d,cmd:%x,len:%d\r\n",
                ts->vc,item->sid,ts->cmd,item->tlen);
        }
    }

    g_stat_info.sendreqnum++;
    return OMIP_OK;
    
}

int omip_recv(omip_transaction *ts)
{

    omip_sock *sock;
    omip_recv_assemble msg;
    unsigned int msg_len = sizeof(msg);
    int ret;

    if(ts == NULL || ts->data == NULL || ts->len == 0)
    {
        omip_printf(OMIP_ERROR_FLASH,"====para invalid(%p), data(%p), len(%d)\r\n", ts, ts->data, ts->len);
        return OMIP_PARAS_INVALID;
    }

    if(ts->vc < OMIP_VC_CHANNEL_RESERVED || ts->vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR_FLASH,"====vc(%d) is invalid, only can be from 4 to 15.[%s,%d]\r\n",ts->vc,__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }

    if(gp_omip_context->sock[ts->vc].used == 0)
    {
        omip_printf(OMIP_ERROR_FLASH,"====vc(%d) is not opened.[%s,%d]\r\n",ts->vc,__FUNCTION__,__LINE__);
        return OMIP_VC_NOT_OPENED;
    }

    (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));

    sock = &gp_omip_context->sock[ts->vc];
    ret = osal_queue_recv(sock->recv_queue, &msg, msg_len, ts->timeout);
    if(OSAL_OK == ret)
    {
        omip_printf(OMIP_DEBUG,"user receive msg, cmd:%x, sid:%d,totol len:%d.[%s,%d]\r\n",
            msg.cmd, msg.sid, msg.tlen,__FUNCTION__,__LINE__);

        if(msg.tlen > ts->len)
        {
            omip_printf(OMIP_ERROR_FLASH,"msg len(%d) exceed user buffer(%d).[%s,%d]\r\n",
                msg.tlen, ts->len, __FUNCTION__,__LINE__);
            omip_free_frame_list(&msg);
            return OMIP_LENGTH_INVALID;
        }
        ts->cmd = msg.cmd;
        ts->ctf = msg.ct;
        ts->relay_flag = msg.relay_flag;
        ts->relay_vc = msg.relay_vc;
        omip_get_frame_list(&msg,ts->data);
        omip_free_frame_list(&msg);
        return msg.tlen;
    }
    else if(OSAL_TIMEOUT == ret)
    {
        return OMIP_QUEUE_RECV_TIMEOUT;
    }
    else
    {
        //omip_printf(OMIP_ERROR_FLASH,"====read queue failed(%x).[%s,%d]\r\n",ret,__FUNCTION__,__LINE__);
        return OMIP_READ_QUEUE_ERROR;
    }

}



int omip_api_open_vc(unsigned char vc, omip_qos_level level, const char *app_name)
{
    return omip_open_vc(vc,level,app_name,0);
}

int omip_api_send(unsigned char vc, unsigned char ct, unsigned short cmd, unsigned char *data, unsigned int len)
{
    omip_transaction ts = {0};
    ts.vc      = vc;
    ts.ctf     = ct;
    ts.cmd     = cmd;
    ts.data    = data;
    ts.len     = len;
    ts.timeout = OMIP_SEND_DEFAULT;
    return omip_send(&ts);
}

int omip_api_recv(unsigned char vc, unsigned char *ct, unsigned short *cmd, unsigned char *data, unsigned int len)
{
    int ret;
    omip_transaction ts = {0};

    ts.vc   = vc;
    ts.data = data;
    ts.len  =len;
    ts.timeout = OMIP_RECV_DEFAULT;
    
    ret = omip_recv(&ts);
    if(ret >= 0)
    {
        *ct  = ts.ctf;
        *cmd = ts.cmd;
    }
    return ret;

}

void omip_api_close(unsigned char vc, const char *app_name)
{
    omip_close_vc(vc,app_name);
}
    
//called by hlink_omip_app
int omip_recv_connect_req(unsigned char vc, unsigned char sid, unsigned char *data, unsigned short len)
{
    omip_context_s *context = gp_omip_context;
    omip_sock *sock = &context->sock[vc];
    
    (void)data;
    (void)len;
    
    if(sock->used == 0)
    {
        omip_printf(OMIP_INFO ,"====sock(%d) is not opend![%s,%d]\r\n",
            vc,__FUNCTION__,__LINE__);
        return OMIP_VC_NOT_OPENED;
    }
    

    if(sock->connect_state == OMIP_CONNECT_STATE_DONE_OK) {
        sock->exp_sid = 0xFF;
        omip_free_sendlist(&sock->head_unack);
        sock->unack_num = 0;
        
        (void)osal_mutex_lock(sock->user_send_mutex);
        omip_free_sendlist(&sock->head_unsent);
        sock->unsent_num = 0;
        (void)osal_mutex_unlock(sock->user_send_mutex);
        for(int i = 0; i < OMIP_MAX_ASSEMBLE_NUM; i++)
        {
            if((sock->assemble_head[i].used != OMIP_REASSEMBLE_NONE) && (sock->assemble_head[i].sid != sid))
            {
                omip_free_frame_list(&sock->assemble_head[i]);
                memset_s(&sock->assemble_head[i], sizeof(sock->assemble_head[i]),0,sizeof(sock->assemble_head[i]));
                sock->assemble_num++;
            }
        }
        sock->recv_not_expt_msg = 0;
    }
    
    
    sock->recv_left_window = (((unsigned char)(sid+1)) % (OMIP_SID_MAX+1));
    sock->recv_right_window = (((unsigned char)(sid+1+OMIP_SEND_WINDOW_SIZE)) % (OMIP_SID_MAX+1));

    omip_printf(OMIP_INFO ,"omip_recv_connect_req:(vc:%d):sendleft:%d,sendright:%d,recvleft:%d,recvright:%d!\r\n",
            vc,sock->send_left_window,sock->send_right_window,sock->recv_left_window,sock->recv_right_window);
    
    
    return OMIP_OK;
}

int omip_recv_connect_ack(unsigned char vc, unsigned char sid, unsigned char *data, unsigned short len)
{
    omip_context_s *context = gp_omip_context;
    omip_sock *sock = &context->sock[vc];
    
    (void)data;
    (void)len;
    
    sock->recv_left_window = (((unsigned char)(sid+1)) % (OMIP_SID_MAX+1));
    sock->recv_right_window = (((unsigned char)(sid+1+OMIP_SEND_WINDOW_SIZE)) % (OMIP_SID_MAX+1));
        
    omip_printf(OMIP_INFO ,"====omip_recv_connect_ack:(vc:%d):sendleft:%d,sendright:%d,recvleft:%d,recvright:%d!\r\n",
        vc,sock->send_left_window,sock->send_right_window,sock->recv_left_window,sock->recv_right_window);
    
    return OMIP_OK;
}

int omip_shakehand(omip_shakehand_sync *sync)
{ 
    int ret = 0;
    unsigned short cmd; 
    omip_transaction send_ts = {0};
    omip_transaction recv_ts = {0};
    
    if(sync == NULL || sync->data == NULL) {
        return OMIP_ERROR_UNKNOWN;
    }

    omip_context_s *context = gp_omip_context;
    if(context == NULL) {
        return OMIP_ERROR_UNKNOWN;
    }

    omip_sock *sock = &context->sock[sync->vc];
    struct omip_config_info config = {0};

    struct omip_config_info *peer_config = NULL;
    unsigned int sendreq_recvack_timeout = 0;
    unsigned int sendreq_recvreq_timeout = 0;
    unsigned int not_expect_msg = 0;

    
    send_ts.vc      = sync->vc;
    send_ts.ctf     = OMIP_CONTENT_FORMAT_BINARY;
    send_ts.data    = (unsigned char *)&config;
    send_ts.len     = (unsigned short)sizeof(config);
    send_ts.timeout = OMIP_SEND_DEFAULT;

    recv_ts.vc      = sync->vc;
    recv_ts.data    = sync->data;
    recv_ts.len     = sync->len;
    recv_ts.timeout = sync->timeout;
    
    if((int)sync->vc < (int)OMIP_VC_CHANNEL_RESERVED || (int)sync->vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR,"====vc can only be from 4 to 15.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }
    
    omip_random_bytes(&config.magic, sizeof(unsigned int));
    config.major = OMIP_MAJOR;
    config.minor = OMIP_MINOR;
    config.qos = (unsigned char)context->sock[sync->vc].level;
    config.sid_overflow_num = context->sock[sync->vc].sid_local_overflow_num;

    omip_printf(OMIP_INFO, "omip_api_shakehand====>>>>local version:%s,local qos:%d,tm:%d\r\n",
            OMIP_VER,config.qos,recv_ts.timeout);

    if(sync->reconnect_flag)
    {
        peer_config = (struct omip_config_info *)recv_ts.data;
        omip_printf(OMIP_INFO, "===+++=>>>>peer version:%d-%d,qos:%d\n",peer_config->major,peer_config->minor,peer_config->qos);
        cmd = OMIP_SYS_CMD_CONNECT;
    }
    else {
        ret = omip_recv(&recv_ts);
        if(ret > 0) { 
            peer_config = (struct omip_config_info *)recv_ts.data;
            cmd = recv_ts.cmd;
        }
        else
        {
            cmd = 0xFFFF;
        }
    }
    
    while(1)
    {   
        omip_printf(OMIP_INFO, "====>>>>sock->connect_state:%d,cmd:%x,ret:%d\r\n",
            sock->connect_state,cmd,ret);
        if(ret > 0)
            omip_printf(OMIP_INFO, "====>>>>peer version:%d-%d,qos:%d\r\n",peer_config->major,peer_config->minor,peer_config->qos);
        
        switch (sock->connect_state) {
            case OMIP_CONNECT_STATE_INIT:
                
                if((ret >= 0) && (cmd == OMIP_SYS_CMD_CONNECT))
                {
                    send_ts.cmd = OMIP_SYS_CMD_CONN_ACK;
                    omip_send(&send_ts);
                    omip_printf(OMIP_INFO, "====>>>>change OMIP_CONNECT_STATE_INIT to OMIP_CONNECT_STATE_SENDREQ_RECVREQ\r\n");
                    sock->connect_state = OMIP_CONNECT_STATE_SENDREQ_RECVREQ;
                
                }
                else
                {
                    omip_printf(OMIP_INFO, "====>>>>change OMIP_CONNECT_STATE_INIT to OMIP_CONNECT_STATE_SENDREQ\r\n");
                    sock->connect_state = OMIP_CONNECT_STATE_SENDREQ;
                }

                send_ts.cmd = OMIP_SYS_CMD_CONNECT;
                omip_send(&send_ts);
                
                break;
            case OMIP_CONNECT_STATE_SENDREQ:
                if((ret >= 0) && (cmd == OMIP_SYS_CMD_CONN_ACK))
                {
                    if(peer_config->qos != OMIP_QOS_2)
                    {
                        sock->connect_state = OMIP_CONNECT_STATE_DOWN_LEVEL;
                        context->sock[sync->vc].level = peer_config->qos;
                        omip_printf(OMIP_INFO, "====>>>>local qos frome 2 to %d\n", peer_config->qos);
                        return (int)peer_config->qos;
                    }
                    sock->connect_state = OMIP_CONNECT_STATE_SENDREQ_RECVACK;
                }
                else if((ret >= 0) && (cmd == OMIP_SYS_CMD_CONNECT))
                {
                    send_ts.cmd = OMIP_SYS_CMD_CONN_ACK;
                    omip_send(&send_ts);
                    omip_printf(OMIP_INFO, "====>>>>change OMIP_CONNECT_STATE_SENDREQ to OMIP_CONNECT_STATE_SENDREQ_RECVREQ\n");
                    sock->connect_state = OMIP_CONNECT_STATE_SENDREQ_RECVREQ;
                }
                else
                {
                    send_ts.cmd = OMIP_SYS_CMD_CONNECT;
                    omip_send(&send_ts);
                    
                }
                break;
            case OMIP_CONNECT_STATE_SENDREQ_RECVACK:
                if((ret >= 0) && (cmd == OMIP_SYS_CMD_CONNECT)) {
                    send_ts.cmd = OMIP_SYS_CMD_CONN_ACK;
                    omip_send(&send_ts);
                    if(peer_config != NULL)
                        sock->sid_remote_overflow_num = peer_config->sid_overflow_num;
                    sock->connect_state = OMIP_CONNECT_STATE_DONE_OK;
                    omip_printf(OMIP_INFO_FLASH, "====>>>>(vc:%d) connect to peer OK!!\r\n", sync->vc);
                    return (int)OMIP_QOS_2;
                    
                }
                else
                {
                    omip_printf(OMIP_INFO, "====>>>>(vc:%d) wait peer OMIP_SYS_CMD_CONNECT,but recv timeout\n", sync->vc);
                    sendreq_recvack_timeout++;
                    if(sendreq_recvack_timeout > 2)
                    {
                        omip_printf(OMIP_INFO, "====>>>>(vc:%d) change from OMIP_CONNECT_STATE_SENDREQ_RECVACK to OMIP_CONNECT_STATE_INIT\n", sync->vc);
                        sock->connect_state = OMIP_CONNECT_STATE_INIT;
                        sendreq_recvack_timeout = 0;
                    }
                }
                break;
            case OMIP_CONNECT_STATE_SENDREQ_RECVREQ:
                if((ret >= 0) && (cmd == OMIP_SYS_CMD_CONN_ACK)) {
                    omip_printf(OMIP_INFO_FLASH, "====>>>>(vc:%d) connect to peer OK!!\r\n", sync->vc);
                    if(peer_config != NULL)
                        sock->sid_remote_overflow_num = peer_config->sid_overflow_num;
                    sock->connect_state = OMIP_CONNECT_STATE_DONE_OK;
                    return (int)OMIP_QOS_2;
                }
                else if((ret >= 0) && (cmd == OMIP_SYS_CMD_CONNECT)) {
                    send_ts.cmd = OMIP_SYS_CMD_CONN_ACK;
                    omip_send(&send_ts);
                    omip_printf(OMIP_INFO, "====>>>>(vc:%d) wait peer OMIP_SYS_CMD_CONN_ACK,but recv OMIP_SYS_CMD_CONNECT\n", sync->vc);
                    
                    not_expect_msg++;
                    if(not_expect_msg > 3)
                    {
                        omip_printf(OMIP_INFO, "====>>>>(vc:%d) change from OMIP_CONNECT_STATE_SENDREQ_RECVREQ to OMIP_CONNECT_STATE_INIT\n", sync->vc);
                        sock->connect_state = OMIP_CONNECT_STATE_INIT;
                        not_expect_msg = 0;
                    }
                    
                }
                else
                {
                    omip_printf(OMIP_INFO, "====>>>>(vc:%d) wait peer OMIP_SYS_CMD_CONN_ACK,but recv timeout\n", sync->vc);
                    send_ts.cmd = OMIP_SYS_CMD_CONNECT;
                    omip_send(&send_ts);
                    sendreq_recvreq_timeout++;
                    if(sendreq_recvreq_timeout > 3)
                    {
                        omip_printf(OMIP_INFO, "====>>>>(vc:%d) change from OMIP_CONNECT_STATE_SENDREQ_RECVREQ to OMIP_CONNECT_STATE_INIT\n", sync->vc);
                        sock->connect_state = OMIP_CONNECT_STATE_INIT;
                        sendreq_recvreq_timeout = 0;
                    }
                        
                }
                break;
            case OMIP_CONNECT_STATE_DONE_OK:
                if(cmd == OMIP_SYS_CMD_CONNECT) {
                    omip_printf(OMIP_INFO, "====>>>>(vc:%d) recv OMIP_SYS_CMD_CONNECT when in OMIP_CONNECT_STATE_DONE_OK\n", sync->vc); 
                    send_ts.cmd = OMIP_SYS_CMD_CONN_ACK;
                    omip_send(&send_ts);
                    
                    send_ts.cmd = OMIP_SYS_CMD_CONNECT;
                    omip_send(&send_ts);
                    
                    sock->connect_state = OMIP_CONNECT_STATE_SENDREQ_RECVREQ;
                }
                else
                {
                    
                }
                break;
            case OMIP_CONNECT_STATE_DOWN_LEVEL:
                if(cmd == OMIP_SYS_CMD_CONNECT)
                {
                    omip_printf(OMIP_INFO, "====>>>>(vc:%d) error!!!recv OMIP_SYS_CMD_CONNECT when in OMIP_CONNECT_STATE_DOWN_LEVEL\n", sync->vc); 
                }
                break;
            default:
                return OMIP_ERROR_UNKNOWN;
        }
        
        ret = omip_recv(&recv_ts);
                
        if((ret >= 0) && ((recv_ts.cmd == OMIP_SYS_CMD_CONNECT) || (recv_ts.cmd == OMIP_SYS_CMD_CONN_ACK)))
        {
            peer_config = (struct omip_config_info *)recv_ts.data;
            cmd = recv_ts.cmd;
        }
        else
        {
            cmd = 0xFFFF;
        }
    }

    return (int)OMIP_QOS_2;
}

int omip_qos_downlevel(unsigned char vc)
{
    omip_transaction send_ts = {0};
    omip_context_s *context = gp_omip_context;

    struct omip_config_info config = {0};

    if(vc < OMIP_VC_CHANNEL_RESERVED || vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR,"====vc can only be from 4 to 15.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
}

    omip_random_bytes(&config.magic, sizeof(unsigned int));
    config.major = OMIP_MAJOR;
    config.minor = OMIP_MINOR;
    config.qos = (unsigned char)context->sock[vc].level;

    send_ts.vc      = vc;
    send_ts.ctf     = OMIP_CONTENT_FORMAT_BINARY;
    send_ts.data    = (unsigned char *)&config;
    send_ts.len     = (unsigned short)sizeof(config);
    send_ts.timeout = OMIP_SEND_DEFAULT;

    send_ts.cmd = OMIP_SYS_CMD_CONN_ACK;

    omip_printf(OMIP_INFO,"+++++++++++++++++vc:%d, magic:%d,major:%d,minor:%d,config.qos:%d.[%s,%d]\r\n",
        vc,config.magic,config.major,config.minor,config.qos, __FUNCTION__,__LINE__);
    
    return omip_send(&send_ts);
    
    
}

int omip_sys_cmd_handler(void *arg, void *data, unsigned short len)
{
    omip_recv_assemble *p = (omip_recv_assemble *)data;
    unsigned short cmd = p->cmd;

    (void)arg;
    (void)len;
   
    if(p->tlen > OMIP_SYS_CONFIG_DATA_MAX)
    {
        omip_printf(OMIP_ERROR,"msg len(%d) exceed sys config data buffer(%d).[%s,%d]\r\n",
            p->tlen, OMIP_SYS_CONFIG_DATA_MAX, __FUNCTION__,__LINE__);
        
        return OMIP_LENGTH_INVALID;
    }
    
    omip_get_frame_list(p,g_sys_config_data);

    switch(cmd) {
        case OMIP_SYS_CMD_CONNECT:
            omip_recv_connect_req(p->vc, p->sid, g_sys_config_data, p->tlen);
            break;
        case OMIP_SYS_CMD_CONN_ACK:
            omip_recv_connect_ack(p->vc, p->sid, g_sys_config_data, p->tlen);
            break;
        default:
            break;
            
    }
    
    return OMIP_OK;
}

int omip_observe_entry(void *args)
{
    int i = 0;
    (void)args;
    
    for(;;)
    {
        osal_task_sleep(OMIP_OBSERVE_TIME*3);

        for(;i < OMIP_VC_CHANNEL_TOTAL; i++)
        {
            if(gp_omip_context->sock[i].used != OMIP_CHANNEL_OPENED)
            {
                continue;
            }

            omip_printf(OMIP_INFO,"[+++++++++++++++observe vc-%d]connect state:%d,qos:%d,unsent:%d,unack_num:%d\r\n",
                i,gp_omip_context->sock[i].connect_state,(int)gp_omip_context->sock[i].level,
                gp_omip_context->sock[i].unsent_num,
                gp_omip_context->sock[i].unack_num);

            if(gp_omip_context->sock[i].level == OMIP_QOS_2)
            {
                omip_sock *sock = &gp_omip_context->sock[i];
                omip_printf(OMIP_INFO ,"====windows(vc:4):sendleft:%d,sendright:%d,recvleft:%d,recvright:%d!\r\n",
                    sock->send_left_window,sock->send_right_window,sock->recv_left_window,sock->recv_right_window);
            }
            
        }
        omip_printf(OMIP_INFO,"sendreqnum:%d, send_failed:%d, recvacknum:%d,"
            "recvacknum_good:%d, recvacknum_bad:%d recvacknum_not_found:%d\r\n",
            g_stat_info.sendreqnum, g_stat_info.send_failed, g_stat_info.recvacknum,
            g_stat_info.recvacknum_good, g_stat_info.recvacknum_bad, g_stat_info.recvacknum_not_found);

        omip_printf(OMIP_INFO,"recvreqnum:%d, sendacknum:%d, recvebytesnum:%d, recvemsgsnum:%d "
            "max_retrans:%d, max_delay:%d\r\n",
            g_stat_info.recvreqnum, g_stat_info.sendacknum, g_stat_info.recvebytesnum, 
            g_stat_info.recvemsgsnum, g_stat_info.max_retrans, g_stat_info.max_delay);
    }
    
    return 0;
    
}

void omip_start_observe_task(void)
{
    gp_omip_context->observe_handle = osal_task_create("omip_observe_task", omip_observe_entry, NULL, 1024*2, NULL, 6);
}

int omip_module_install(omip_config_paras *para)
{
    int ret;
    if(para == NULL)
    {
        return OMIP_ERROR_UNKNOWN;
    }
    osal_init();
    ret = omip_init(&gp_omip_context);
    #include "omip_uart.h"
    omip_uart_init();
    omip_start_work_task(gp_omip_context, para->task_pri, para->stack_size);
    if(OMIP_OBSERVE_TIME != 0)omip_start_observe_task();
    omip_printf(OMIP_INFO ,"====omip_module_install succ!\r\n");
    return ret;
}

void omip_module_uninstall(void)
{
    osal_task_kill(gp_omip_context->work_handle);
    if(gp_omip_context->observe_handle)
        osal_task_kill(gp_omip_context->observe_handle);
    osal_task_sleep(1000);
    omip_deinit(&gp_omip_context);

}
//register send  func and recv byte func, and omip frame will be injected to this(such as omip over ble frame)
int omip_set_inject_func(int io_id, omip_inject_send send, omip_inject_recv_byte recv_byte)
{
    if(io_id >= OMIP_SUPPORT_MAX_PYS_DEV_NUM)
    {
        return OMIP_ERROR_UNKNOWN;
    }
    
    gp_omip_context->io_p[io_id]->inject_send = send;
    gp_omip_context->io_p[io_id]->inject_recv_byte = recv_byte;
    return OMIP_OK;
}

int omip_set_app_s(unsigned char vc, void *app_s)
{
    if(vc < (int)OMIP_VC_CHANNEL_RESERVED || vc >= (int)OMIP_VC_CHANNEL_TOTAL)
    {
        omip_printf(OMIP_ERROR,"====vc can only be from 4 to 15.[%s,%d]\r\n",__FUNCTION__,__LINE__);
        return OMIP_VC_INVALID;
    }
    gp_omip_context->sock[vc].app_s = app_s;
    return OMIP_OK;
}


